2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, TAG('M', 'm', ' ', ' '));
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
153 PROS_SECTION_OBJECT Section
;
154 PMEMORY_AREA MemoryArea
;
155 PMM_AVL_TABLE AddressSpace
;
156 POBJECT_NAME_INFORMATION ModuleNameInformation
;
157 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
159 /* Get the MM_AVL_TABLE from EPROCESS */
160 if (Address
>= MmSystemRangeStart
)
162 AddressSpace
= MmGetKernelAddressSpace();
166 AddressSpace
= &PsGetCurrentProcess()->VadRoot
;
169 /* Lock address space */
170 MmLockAddressSpace(AddressSpace
);
172 /* Locate the memory area for the process by address */
173 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
175 /* Make sure it's a section view type */
176 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
178 /* Get the section pointer to the SECTION_OBJECT */
179 Section
= MemoryArea
->Data
.SectionData
.Section
;
181 /* Unlock address space */
182 MmUnlockAddressSpace(AddressSpace
);
184 /* Get the filename of the section */
185 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
187 if (NT_SUCCESS(Status
))
189 /* Init modulename */
190 RtlCreateUnicodeString(ModuleName
,
191 ModuleNameInformation
->Name
.Buffer
);
193 /* Free temp taged buffer from MmGetFileNameForSection() */
194 ExFreePoolWithTag(ModuleNameInformation
, TAG('M', 'm', ' ', ' '));
195 DPRINT("Found ModuleName %S by address %p\n",
196 ModuleName
->Buffer
,Address
);
201 /* Unlock address space */
202 MmUnlockAddressSpace(AddressSpace
);
208 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
211 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
212 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
213 * RETURNS: Status of the wait.
216 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
218 LARGE_INTEGER Timeout
;
219 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
221 Timeout
.QuadPart
= -100000000LL; // 10 sec
224 Timeout
.QuadPart
= -100000000; // 10 sec
227 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
232 * FUNCTION: Sets the page op completion event and releases the page op.
233 * ARGUMENTS: PMM_PAGEOP.
234 * RETURNS: In shorter time than it takes you to even read this
235 * description, so don't even think about geting a mug of coffee.
238 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
240 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
241 MmReleasePageOp(PageOp
);
246 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
247 * ARGUMENTS: PFILE_OBJECT to wait for.
248 * RETURNS: Status of the wait.
251 MmspWaitForFileLock(PFILE_OBJECT File
)
253 return STATUS_SUCCESS
;
254 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
259 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
262 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
264 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
266 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
268 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
276 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
278 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
280 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
281 PMM_SECTION_SEGMENT SectionSegments
;
285 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
286 NrSegments
= ImageSectionObject
->NrSegments
;
287 SectionSegments
= ImageSectionObject
->Segments
;
288 for (i
= 0; i
< NrSegments
; i
++)
290 if (SectionSegments
[i
].ReferenceCount
!= 0)
292 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
293 SectionSegments
[i
].ReferenceCount
);
294 KeBugCheck(MEMORY_MANAGEMENT
);
296 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
298 ExFreePool(ImageSectionObject
->Segments
);
299 ExFreePool(ImageSectionObject
);
300 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
302 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
304 PMM_SECTION_SEGMENT Segment
;
306 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
309 if (Segment
->ReferenceCount
!= 0)
311 DPRINT1("Data segment still referenced\n");
312 KeBugCheck(MEMORY_MANAGEMENT
);
314 MmFreePageTablesSectionSegment(Segment
);
316 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
322 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
324 ExAcquireFastMutex(&Segment
->Lock
);
329 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
331 ExReleaseFastMutex(&Segment
->Lock
);
336 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
340 PSECTION_PAGE_TABLE Table
;
341 ULONG DirectoryOffset
;
344 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
346 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
350 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
351 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
355 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
356 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
357 TAG_SECTION_PAGE_TABLE
);
360 KeBugCheck(MEMORY_MANAGEMENT
);
362 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
363 DPRINT("Table %x\n", Table
);
366 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
367 Table
->Entry
[TableOffset
] = Entry
;
373 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
376 PSECTION_PAGE_TABLE Table
;
378 ULONG DirectoryOffset
;
381 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
383 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
385 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
389 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
390 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
391 DPRINT("Table %x\n", Table
);
397 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
398 Entry
= Table
->Entry
[TableOffset
];
404 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
409 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
412 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
413 KeBugCheck(MEMORY_MANAGEMENT
);
415 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
417 DPRINT1("Maximum share count reached\n");
418 KeBugCheck(MEMORY_MANAGEMENT
);
420 if (IS_SWAP_FROM_SSE(Entry
))
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
430 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
431 PMM_SECTION_SEGMENT Segment
,
437 BOOLEAN IsDirectMapped
= FALSE
;
439 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
442 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
447 DPRINT1("Zero share count for unshare\n");
448 KeBugCheck(MEMORY_MANAGEMENT
);
450 if (IS_SWAP_FROM_SSE(Entry
))
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
456 * If we reducing the share count of this entry to zero then set the entry
457 * to zero and tell the cache the page is no longer mapped.
459 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
461 PFILE_OBJECT FileObject
;
463 SWAPENTRY SavedSwapEntry
;
465 BOOLEAN IsImageSection
;
468 FileOffset
= Offset
+ Segment
->FileOffset
;
470 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
472 Page
= PFN_FROM_SSE(Entry
);
473 FileObject
= Section
->FileObject
;
474 if (FileObject
!= NULL
&&
475 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
478 if ((FileOffset
% PAGE_SIZE
) == 0 &&
479 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
482 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
483 IsDirectMapped
= TRUE
;
484 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
488 KeBugCheck(MEMORY_MANAGEMENT
);
493 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
494 if (SavedSwapEntry
== 0)
497 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
498 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
502 * Try to page out this page and set the swap entry
503 * within the section segment. There exist no rmap entry
504 * for this page. The pager thread can't page out a
505 * page without a rmap entry.
507 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
511 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
514 MmReleasePageMemoryConsumer(MC_USER
, Page
);
520 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
521 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
529 * We hold all locks. Nobody can do something with the current
530 * process and the current segment (also not within an other process).
533 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
540 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
541 MmSetSavedSwapEntryPage(Page
, 0);
543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
547 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
548 KeBugCheck(MEMORY_MANAGEMENT
);
554 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
556 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
559 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
562 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
565 PCACHE_SEGMENT CacheSeg
;
566 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
567 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
579 MiReadPage(PMEMORY_AREA MemoryArea
,
583 * FUNCTION: Read a page for a section backed memory area.
585 * MemoryArea - Memory area to read the page for.
586 * Offset - Offset of the page to read.
587 * Page - Variable that receives a page contains the read data.
594 PCACHE_SEGMENT CacheSeg
;
595 PFILE_OBJECT FileObject
;
599 BOOLEAN IsImageSection
;
602 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
603 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
604 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
605 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
606 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
610 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
613 * If the file system is letting us go directly to the cache and the
614 * memory area was mapped at an offset in the file which is page aligned
615 * then get the related cache segment.
617 if ((FileOffset
% PAGE_SIZE
) == 0 &&
618 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
619 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
623 * Get the related cache segment; we use a lower level interface than
624 * filesystems do because it is safe for us to use an offset with a
625 * alignment less than the file system block size.
627 Status
= CcRosGetCacheSegment(Bcb
,
633 if (!NT_SUCCESS(Status
))
640 * If the cache segment isn't up to date then call the file
641 * system to read in the data.
643 Status
= ReadCacheSegment(CacheSeg
);
644 if (!NT_SUCCESS(Status
))
646 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
651 * Retrieve the page from the cache segment that we actually want.
653 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
654 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
656 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
661 ULONG CacheSegOffset
;
663 * Allocate a page, this is rather complicated by the possibility
664 * we might have to move other things out of memory
666 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
667 if (!NT_SUCCESS(Status
))
671 Status
= CcRosGetCacheSegment(Bcb
,
677 if (!NT_SUCCESS(Status
))
684 * If the cache segment isn't up to date then call the file
685 * system to read in the data.
687 Status
= ReadCacheSegment(CacheSeg
);
688 if (!NT_SUCCESS(Status
))
690 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
694 PageAddr
= MmCreateHyperspaceMapping(*Page
);
695 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
696 Length
= RawLength
- SegOffset
;
697 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
699 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
701 else if (CacheSegOffset
>= PAGE_SIZE
)
703 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
707 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
708 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
709 Status
= CcRosGetCacheSegment(Bcb
,
710 FileOffset
+ CacheSegOffset
,
715 if (!NT_SUCCESS(Status
))
717 MmDeleteHyperspaceMapping(PageAddr
);
723 * If the cache segment isn't up to date then call the file
724 * system to read in the data.
726 Status
= ReadCacheSegment(CacheSeg
);
727 if (!NT_SUCCESS(Status
))
729 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
730 MmDeleteHyperspaceMapping(PageAddr
);
734 if (Length
< PAGE_SIZE
)
736 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
740 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
743 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
744 MmDeleteHyperspaceMapping(PageAddr
);
746 return(STATUS_SUCCESS
);
751 MmNotPresentFaultSectionView(PMM_AVL_TABLE AddressSpace
,
752 MEMORY_AREA
* MemoryArea
,
760 PROS_SECTION_OBJECT Section
;
761 PMM_SECTION_SEGMENT Segment
;
767 BOOLEAN HasSwapEntry
;
768 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
771 * There is a window between taking the page fault and locking the
772 * address space when another thread could load the page so we check
775 if (MmIsPagePresent(Process
, Address
))
779 MmLockPage(MmGetPfnForProcess(Process
, Address
));
781 return(STATUS_SUCCESS
);
784 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
785 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
786 + MemoryArea
->Data
.SectionData
.ViewOffset
;
788 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
789 Section
= MemoryArea
->Data
.SectionData
.Section
;
790 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
791 &MemoryArea
->Data
.SectionData
.RegionListHead
,
796 MmLockSectionSegment(Segment
);
799 * Check if this page needs to be mapped COW
801 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
802 (Region
->Protect
== PAGE_READWRITE
||
803 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
805 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
809 Attributes
= Region
->Protect
;
813 * Get or create a page operation descriptor
815 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
818 DPRINT1("MmGetPageOp failed\n");
819 KeBugCheck(MEMORY_MANAGEMENT
);
823 * Check if someone else is already handling this fault, if so wait
826 if (PageOp
->Thread
!= PsGetCurrentThread())
828 MmUnlockSectionSegment(Segment
);
829 MmUnlockAddressSpace(AddressSpace
);
830 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
832 * Check for various strange conditions
834 if (Status
!= STATUS_SUCCESS
)
836 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
837 KeBugCheck(MEMORY_MANAGEMENT
);
839 if (PageOp
->Status
== STATUS_PENDING
)
841 DPRINT1("Woke for page op before completion\n");
842 KeBugCheck(MEMORY_MANAGEMENT
);
844 MmLockAddressSpace(AddressSpace
);
846 * If this wasn't a pagein then restart the operation
848 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
850 MmspCompleteAndReleasePageOp(PageOp
);
851 DPRINT("Address 0x%.8X\n", Address
);
852 return(STATUS_MM_RESTART_OPERATION
);
856 * If the thread handling this fault has failed then we don't retry
858 if (!NT_SUCCESS(PageOp
->Status
))
860 Status
= PageOp
->Status
;
861 MmspCompleteAndReleasePageOp(PageOp
);
862 DPRINT("Address 0x%.8X\n", Address
);
865 MmLockSectionSegment(Segment
);
867 * If the completed fault was for another address space then set the
870 if (!MmIsPagePresent(Process
, Address
))
872 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
873 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
875 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
878 * The page was a private page in another or in our address space
880 MmUnlockSectionSegment(Segment
);
881 MmspCompleteAndReleasePageOp(PageOp
);
882 return(STATUS_MM_RESTART_OPERATION
);
885 Page
= PFN_FROM_SSE(Entry
);
887 MmSharePageEntrySectionSegment(Segment
, Offset
);
889 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
890 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
892 Status
= MmCreateVirtualMapping(Process
,
897 if (!NT_SUCCESS(Status
))
899 DPRINT1("Unable to create virtual mapping\n");
900 KeBugCheck(MEMORY_MANAGEMENT
);
902 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
908 MmUnlockSectionSegment(Segment
);
909 PageOp
->Status
= STATUS_SUCCESS
;
910 MmspCompleteAndReleasePageOp(PageOp
);
911 DPRINT("Address 0x%.8X\n", Address
);
912 return(STATUS_SUCCESS
);
915 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
919 * Must be private page we have swapped out.
926 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
928 DPRINT1("Found a swaped out private page in a pagefile section.\n");
929 KeBugCheck(MEMORY_MANAGEMENT
);
932 MmUnlockSectionSegment(Segment
);
933 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
935 MmUnlockAddressSpace(AddressSpace
);
936 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
937 if (!NT_SUCCESS(Status
))
939 KeBugCheck(MEMORY_MANAGEMENT
);
942 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
943 if (!NT_SUCCESS(Status
))
945 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
946 KeBugCheck(MEMORY_MANAGEMENT
);
948 MmLockAddressSpace(AddressSpace
);
949 Status
= MmCreateVirtualMapping(Process
,
954 if (!NT_SUCCESS(Status
))
956 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
957 KeBugCheck(MEMORY_MANAGEMENT
);
962 * Store the swap entry for later use.
964 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
967 * Add the page to the process's working set
969 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
972 * Finish the operation
978 PageOp
->Status
= STATUS_SUCCESS
;
979 MmspCompleteAndReleasePageOp(PageOp
);
980 DPRINT("Address 0x%.8X\n", Address
);
981 return(STATUS_SUCCESS
);
985 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
987 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
989 MmUnlockSectionSegment(Segment
);
991 * Just map the desired physical page
993 Page
= Offset
>> PAGE_SHIFT
;
994 Status
= MmCreateVirtualMappingUnsafe(Process
,
999 if (!NT_SUCCESS(Status
))
1001 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1002 KeBugCheck(MEMORY_MANAGEMENT
);
1006 * Don't add an rmap entry since the page mapped could be for
1011 MmLockPageUnsafe(Page
);
1015 * Cleanup and release locks
1017 PageOp
->Status
= STATUS_SUCCESS
;
1018 MmspCompleteAndReleasePageOp(PageOp
);
1019 DPRINT("Address 0x%.8X\n", Address
);
1020 return(STATUS_SUCCESS
);
1024 * Map anonymous memory for BSS sections
1026 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1028 MmUnlockSectionSegment(Segment
);
1029 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1030 if (!NT_SUCCESS(Status
))
1032 MmUnlockAddressSpace(AddressSpace
);
1033 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1034 MmLockAddressSpace(AddressSpace
);
1036 if (!NT_SUCCESS(Status
))
1038 KeBugCheck(MEMORY_MANAGEMENT
);
1040 Status
= MmCreateVirtualMapping(Process
,
1045 if (!NT_SUCCESS(Status
))
1047 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1048 KeBugCheck(MEMORY_MANAGEMENT
);
1051 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1058 * Cleanup and release locks
1060 PageOp
->Status
= STATUS_SUCCESS
;
1061 MmspCompleteAndReleasePageOp(PageOp
);
1062 DPRINT("Address 0x%.8X\n", Address
);
1063 return(STATUS_SUCCESS
);
1067 * Get the entry corresponding to the offset within the section
1069 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1074 * If the entry is zero (and it can't change because we have
1075 * locked the segment) then we need to load the page.
1079 * Release all our locks and read in the page from disk
1081 MmUnlockSectionSegment(Segment
);
1082 MmUnlockAddressSpace(AddressSpace
);
1084 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1085 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1087 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1088 if (!NT_SUCCESS(Status
))
1090 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1095 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1096 if (!NT_SUCCESS(Status
))
1098 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1101 if (!NT_SUCCESS(Status
))
1104 * FIXME: What do we know in this case?
1107 * Cleanup and release locks
1109 MmLockAddressSpace(AddressSpace
);
1110 PageOp
->Status
= Status
;
1111 MmspCompleteAndReleasePageOp(PageOp
);
1112 DPRINT("Address 0x%.8X\n", Address
);
1116 * Relock the address space and segment
1118 MmLockAddressSpace(AddressSpace
);
1119 MmLockSectionSegment(Segment
);
1122 * Check the entry. No one should change the status of a page
1123 * that has a pending page-in.
1125 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1126 if (Entry
!= Entry1
)
1128 DPRINT1("Someone changed ppte entry while we slept\n");
1129 KeBugCheck(MEMORY_MANAGEMENT
);
1133 * Mark the offset within the section as having valid, in-memory
1136 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1137 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1138 MmUnlockSectionSegment(Segment
);
1140 Status
= MmCreateVirtualMapping(Process
,
1145 if (!NT_SUCCESS(Status
))
1147 DPRINT1("Unable to create virtual mapping\n");
1148 KeBugCheck(MEMORY_MANAGEMENT
);
1150 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1156 PageOp
->Status
= STATUS_SUCCESS
;
1157 MmspCompleteAndReleasePageOp(PageOp
);
1158 DPRINT("Address 0x%.8X\n", Address
);
1159 return(STATUS_SUCCESS
);
1161 else if (IS_SWAP_FROM_SSE(Entry
))
1163 SWAPENTRY SwapEntry
;
1165 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1168 * Release all our locks and read in the page from disk
1170 MmUnlockSectionSegment(Segment
);
1172 MmUnlockAddressSpace(AddressSpace
);
1174 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1175 if (!NT_SUCCESS(Status
))
1177 KeBugCheck(MEMORY_MANAGEMENT
);
1180 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1181 if (!NT_SUCCESS(Status
))
1183 KeBugCheck(MEMORY_MANAGEMENT
);
1187 * Relock the address space and segment
1189 MmLockAddressSpace(AddressSpace
);
1190 MmLockSectionSegment(Segment
);
1193 * Check the entry. No one should change the status of a page
1194 * that has a pending page-in.
1196 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1197 if (Entry
!= Entry1
)
1199 DPRINT1("Someone changed ppte entry while we slept\n");
1200 KeBugCheck(MEMORY_MANAGEMENT
);
1204 * Mark the offset within the section as having valid, in-memory
1207 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1208 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1209 MmUnlockSectionSegment(Segment
);
1212 * Save the swap entry.
1214 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1215 Status
= MmCreateVirtualMapping(Process
,
1220 if (!NT_SUCCESS(Status
))
1222 DPRINT1("Unable to create virtual mapping\n");
1223 KeBugCheck(MEMORY_MANAGEMENT
);
1225 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1230 PageOp
->Status
= STATUS_SUCCESS
;
1231 MmspCompleteAndReleasePageOp(PageOp
);
1232 DPRINT("Address 0x%.8X\n", Address
);
1233 return(STATUS_SUCCESS
);
1238 * If the section offset is already in-memory and valid then just
1239 * take another reference to the page
1242 Page
= PFN_FROM_SSE(Entry
);
1244 MmSharePageEntrySectionSegment(Segment
, Offset
);
1245 MmUnlockSectionSegment(Segment
);
1247 Status
= MmCreateVirtualMapping(Process
,
1252 if (!NT_SUCCESS(Status
))
1254 DPRINT1("Unable to create virtual mapping\n");
1255 KeBugCheck(MEMORY_MANAGEMENT
);
1257 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1262 PageOp
->Status
= STATUS_SUCCESS
;
1263 MmspCompleteAndReleasePageOp(PageOp
);
1264 DPRINT("Address 0x%.8X\n", Address
);
1265 return(STATUS_SUCCESS
);
1271 MmAccessFaultSectionView(PMM_AVL_TABLE AddressSpace
,
1272 MEMORY_AREA
* MemoryArea
,
1276 PMM_SECTION_SEGMENT Segment
;
1277 PROS_SECTION_OBJECT Section
;
1286 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1288 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1291 * Check if the page has been paged out or has already been set readwrite
1293 if (!MmIsPagePresent(Process
, Address
) ||
1294 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1296 DPRINT("Address 0x%.8X\n", Address
);
1297 return(STATUS_SUCCESS
);
1301 * Find the offset of the page
1303 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1304 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1305 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1307 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1308 Section
= MemoryArea
->Data
.SectionData
.Section
;
1309 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1310 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1315 MmLockSectionSegment(Segment
);
1317 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1318 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1320 MmUnlockSectionSegment(Segment
);
1323 * Check if we are doing COW
1325 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1326 (Region
->Protect
== PAGE_READWRITE
||
1327 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1329 DPRINT("Address 0x%.8X\n", Address
);
1330 return(STATUS_ACCESS_VIOLATION
);
1333 if (IS_SWAP_FROM_SSE(Entry
) ||
1334 PFN_FROM_SSE(Entry
) != OldPage
)
1336 /* This is a private page. We must only change the page protection. */
1337 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1338 return(STATUS_SUCCESS
);
1342 * Get or create a pageop
1344 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1345 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1348 DPRINT1("MmGetPageOp failed\n");
1349 KeBugCheck(MEMORY_MANAGEMENT
);
1353 * Wait for any other operations to complete
1355 if (PageOp
->Thread
!= PsGetCurrentThread())
1357 MmUnlockAddressSpace(AddressSpace
);
1358 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1360 * Check for various strange conditions
1362 if (Status
== STATUS_TIMEOUT
)
1364 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1365 KeBugCheck(MEMORY_MANAGEMENT
);
1367 if (PageOp
->Status
== STATUS_PENDING
)
1369 DPRINT1("Woke for page op before completion\n");
1370 KeBugCheck(MEMORY_MANAGEMENT
);
1373 * Restart the operation
1375 MmLockAddressSpace(AddressSpace
);
1376 MmspCompleteAndReleasePageOp(PageOp
);
1377 DPRINT("Address 0x%.8X\n", Address
);
1378 return(STATUS_MM_RESTART_OPERATION
);
1382 * Release locks now we have the pageop
1384 MmUnlockAddressSpace(AddressSpace
);
1389 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1390 if (!NT_SUCCESS(Status
))
1392 KeBugCheck(MEMORY_MANAGEMENT
);
1398 MiCopyFromUserPage(NewPage
, PAddress
);
1400 MmLockAddressSpace(AddressSpace
);
1402 * Delete the old entry.
1404 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1407 * Set the PTE to point to the new page
1409 Status
= MmCreateVirtualMapping(Process
,
1414 if (!NT_SUCCESS(Status
))
1416 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1420 if (!NT_SUCCESS(Status
))
1422 DPRINT1("Unable to create virtual mapping\n");
1423 KeBugCheck(MEMORY_MANAGEMENT
);
1427 MmLockPage(NewPage
);
1428 MmUnlockPage(OldPage
);
1432 * Unshare the old page.
1434 MmDeleteRmap(OldPage
, Process
, PAddress
);
1435 MmInsertRmap(NewPage
, Process
, PAddress
);
1436 MmLockSectionSegment(Segment
);
1437 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1438 MmUnlockSectionSegment(Segment
);
1440 PageOp
->Status
= STATUS_SUCCESS
;
1441 MmspCompleteAndReleasePageOp(PageOp
);
1442 DPRINT("Address 0x%.8X\n", Address
);
1443 return(STATUS_SUCCESS
);
1447 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1449 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1453 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1456 MmLockAddressSpace(&Process
->VadRoot
);
1459 MmDeleteVirtualMapping(Process
,
1466 PageOutContext
->WasDirty
= TRUE
;
1468 if (!PageOutContext
->Private
)
1470 MmLockSectionSegment(PageOutContext
->Segment
);
1471 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1472 PageOutContext
->Segment
,
1473 PageOutContext
->Offset
,
1474 PageOutContext
->WasDirty
,
1476 MmUnlockSectionSegment(PageOutContext
->Segment
);
1480 MmUnlockAddressSpace(&Process
->VadRoot
);
1483 if (PageOutContext
->Private
)
1485 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1488 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1493 MmPageOutSectionView(PMM_AVL_TABLE AddressSpace
,
1494 MEMORY_AREA
* MemoryArea
,
1499 MM_SECTION_PAGEOUT_CONTEXT Context
;
1500 SWAPENTRY SwapEntry
;
1504 PFILE_OBJECT FileObject
;
1506 BOOLEAN DirectMapped
;
1507 BOOLEAN IsImageSection
;
1508 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1510 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1513 * Get the segment and section.
1515 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1516 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1518 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1519 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1520 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1522 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1524 FileObject
= Context
.Section
->FileObject
;
1525 DirectMapped
= FALSE
;
1526 if (FileObject
!= NULL
&&
1527 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1529 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1532 * If the file system is letting us go directly to the cache and the
1533 * memory area was mapped at an offset in the file which is page aligned
1534 * then note this is a direct mapped page.
1536 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1537 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1539 DirectMapped
= TRUE
;
1545 * This should never happen since mappings of physical memory are never
1546 * placed in the rmap lists.
1548 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1550 DPRINT1("Trying to page out from physical memory section address 0x%X "
1551 "process %d\n", Address
,
1552 Process
? Process
->UniqueProcessId
: 0);
1553 KeBugCheck(MEMORY_MANAGEMENT
);
1557 * Get the section segment entry and the physical address.
1559 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1560 if (!MmIsPagePresent(Process
, Address
))
1562 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1563 Process
? Process
->UniqueProcessId
: 0, Address
);
1564 KeBugCheck(MEMORY_MANAGEMENT
);
1566 Page
= MmGetPfnForProcess(Process
, Address
);
1567 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1570 * Prepare the context structure for the rmap delete call.
1572 Context
.WasDirty
= FALSE
;
1573 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1574 IS_SWAP_FROM_SSE(Entry
) ||
1575 PFN_FROM_SSE(Entry
) != Page
)
1577 Context
.Private
= TRUE
;
1581 Context
.Private
= FALSE
;
1585 * Take an additional reference to the page or the cache segment.
1587 if (DirectMapped
&& !Context
.Private
)
1589 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1591 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1592 KeBugCheck(MEMORY_MANAGEMENT
);
1597 MmReferencePage(Page
);
1600 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1603 * If this wasn't a private page then we should have reduced the entry to
1604 * zero by deleting all the rmaps.
1606 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1608 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1609 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1611 KeBugCheck(MEMORY_MANAGEMENT
);
1616 * If the page wasn't dirty then we can just free it as for a readonly page.
1617 * Since we unmapped all the mappings above we know it will not suddenly
1619 * If the page is from a pagefile section and has no swap entry,
1620 * we can't free the page at this point.
1622 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1623 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1625 if (Context
.Private
)
1627 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1628 Context
.WasDirty
? "dirty" : "clean", Address
);
1629 KeBugCheck(MEMORY_MANAGEMENT
);
1631 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1633 MmSetSavedSwapEntryPage(Page
, 0);
1634 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1635 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1636 PageOp
->Status
= STATUS_SUCCESS
;
1637 MmspCompleteAndReleasePageOp(PageOp
);
1638 return(STATUS_SUCCESS
);
1641 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1643 if (Context
.Private
)
1645 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1646 Context
.WasDirty
? "dirty" : "clean", Address
);
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1649 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1651 MmSetSavedSwapEntryPage(Page
, 0);
1654 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1656 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1657 PageOp
->Status
= STATUS_SUCCESS
;
1658 MmspCompleteAndReleasePageOp(PageOp
);
1659 return(STATUS_SUCCESS
);
1662 else if (!Context
.Private
&& DirectMapped
)
1666 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1668 KeBugCheck(MEMORY_MANAGEMENT
);
1670 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1671 if (!NT_SUCCESS(Status
))
1673 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1674 KeBugCheck(MEMORY_MANAGEMENT
);
1676 PageOp
->Status
= STATUS_SUCCESS
;
1677 MmspCompleteAndReleasePageOp(PageOp
);
1678 return(STATUS_SUCCESS
);
1680 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1684 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1686 KeBugCheck(MEMORY_MANAGEMENT
);
1688 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1689 PageOp
->Status
= STATUS_SUCCESS
;
1690 MmspCompleteAndReleasePageOp(PageOp
);
1691 return(STATUS_SUCCESS
);
1693 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1695 MmSetSavedSwapEntryPage(Page
, 0);
1696 MmLockAddressSpace(AddressSpace
);
1697 Status
= MmCreatePageFileMapping(Process
,
1700 MmUnlockAddressSpace(AddressSpace
);
1701 if (!NT_SUCCESS(Status
))
1703 KeBugCheck(MEMORY_MANAGEMENT
);
1705 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1706 PageOp
->Status
= STATUS_SUCCESS
;
1707 MmspCompleteAndReleasePageOp(PageOp
);
1708 return(STATUS_SUCCESS
);
1712 * If necessary, allocate an entry in the paging file for this page
1716 SwapEntry
= MmAllocSwapPage();
1719 MmShowOutOfSpaceMessagePagingFile();
1720 MmLockAddressSpace(AddressSpace
);
1722 * For private pages restore the old mappings.
1724 if (Context
.Private
)
1726 Status
= MmCreateVirtualMapping(Process
,
1728 MemoryArea
->Protect
,
1731 MmSetDirtyPage(Process
, Address
);
1739 * For non-private pages if the page wasn't direct mapped then
1740 * set it back into the section segment entry so we don't loose
1741 * our copy. Otherwise it will be handled by the cache manager.
1743 Status
= MmCreateVirtualMapping(Process
,
1745 MemoryArea
->Protect
,
1748 MmSetDirtyPage(Process
, Address
);
1752 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1753 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1755 MmUnlockAddressSpace(AddressSpace
);
1756 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1757 MmspCompleteAndReleasePageOp(PageOp
);
1758 return(STATUS_PAGEFILE_QUOTA
);
1763 * Write the page to the pagefile
1765 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1766 if (!NT_SUCCESS(Status
))
1768 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1771 * As above: undo our actions.
1772 * FIXME: Also free the swap page.
1774 MmLockAddressSpace(AddressSpace
);
1775 if (Context
.Private
)
1777 Status
= MmCreateVirtualMapping(Process
,
1779 MemoryArea
->Protect
,
1782 MmSetDirtyPage(Process
, Address
);
1789 Status
= MmCreateVirtualMapping(Process
,
1791 MemoryArea
->Protect
,
1794 MmSetDirtyPage(Process
, Address
);
1798 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1799 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1801 MmUnlockAddressSpace(AddressSpace
);
1802 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1803 MmspCompleteAndReleasePageOp(PageOp
);
1804 return(STATUS_UNSUCCESSFUL
);
1808 * Otherwise we have succeeded.
1810 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1811 MmSetSavedSwapEntryPage(Page
, 0);
1812 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1813 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1815 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1819 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1822 if (Context
.Private
)
1824 MmLockAddressSpace(AddressSpace
);
1825 Status
= MmCreatePageFileMapping(Process
,
1828 MmUnlockAddressSpace(AddressSpace
);
1829 if (!NT_SUCCESS(Status
))
1831 KeBugCheck(MEMORY_MANAGEMENT
);
1836 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1837 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1840 PageOp
->Status
= STATUS_SUCCESS
;
1841 MmspCompleteAndReleasePageOp(PageOp
);
1842 return(STATUS_SUCCESS
);
1847 MmWritePageSectionView(PMM_AVL_TABLE AddressSpace
,
1848 PMEMORY_AREA MemoryArea
,
1853 PROS_SECTION_OBJECT Section
;
1854 PMM_SECTION_SEGMENT Segment
;
1856 SWAPENTRY SwapEntry
;
1860 PFILE_OBJECT FileObject
;
1862 BOOLEAN DirectMapped
;
1863 BOOLEAN IsImageSection
;
1864 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1866 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1868 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1869 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1872 * Get the segment and section.
1874 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1875 Section
= MemoryArea
->Data
.SectionData
.Section
;
1876 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1878 FileObject
= Section
->FileObject
;
1879 DirectMapped
= FALSE
;
1880 if (FileObject
!= NULL
&&
1881 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1883 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1886 * If the file system is letting us go directly to the cache and the
1887 * memory area was mapped at an offset in the file which is page aligned
1888 * then note this is a direct mapped page.
1890 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1891 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1893 DirectMapped
= TRUE
;
1898 * This should never happen since mappings of physical memory are never
1899 * placed in the rmap lists.
1901 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1903 DPRINT1("Trying to write back page from physical memory mapped at %X "
1904 "process %d\n", Address
,
1905 Process
? Process
->UniqueProcessId
: 0);
1906 KeBugCheck(MEMORY_MANAGEMENT
);
1910 * Get the section segment entry and the physical address.
1912 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1913 if (!MmIsPagePresent(Process
, Address
))
1915 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1916 Process
? Process
->UniqueProcessId
: 0, Address
);
1917 KeBugCheck(MEMORY_MANAGEMENT
);
1919 Page
= MmGetPfnForProcess(Process
, Address
);
1920 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1923 * Check for a private (COWed) page.
1925 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1926 IS_SWAP_FROM_SSE(Entry
) ||
1927 PFN_FROM_SSE(Entry
) != Page
)
1937 * Speculatively set all mappings of the page to clean.
1939 MmSetCleanAllRmaps(Page
);
1942 * If this page was direct mapped from the cache then the cache manager
1943 * will take care of writing it back to disk.
1945 if (DirectMapped
&& !Private
)
1947 ASSERT(SwapEntry
== 0);
1948 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1949 PageOp
->Status
= STATUS_SUCCESS
;
1950 MmspCompleteAndReleasePageOp(PageOp
);
1951 return(STATUS_SUCCESS
);
1955 * If necessary, allocate an entry in the paging file for this page
1959 SwapEntry
= MmAllocSwapPage();
1962 MmSetDirtyAllRmaps(Page
);
1963 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1964 MmspCompleteAndReleasePageOp(PageOp
);
1965 return(STATUS_PAGEFILE_QUOTA
);
1967 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1971 * Write the page to the pagefile
1973 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1974 if (!NT_SUCCESS(Status
))
1976 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1978 MmSetDirtyAllRmaps(Page
);
1979 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1980 MmspCompleteAndReleasePageOp(PageOp
);
1981 return(STATUS_UNSUCCESSFUL
);
1985 * Otherwise we have succeeded.
1987 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1988 PageOp
->Status
= STATUS_SUCCESS
;
1989 MmspCompleteAndReleasePageOp(PageOp
);
1990 return(STATUS_SUCCESS
);
1994 MmAlterViewAttributes(PMM_AVL_TABLE AddressSpace
,
2002 PMEMORY_AREA MemoryArea
;
2003 PMM_SECTION_SEGMENT Segment
;
2004 BOOLEAN DoCOW
= FALSE
;
2006 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2008 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2009 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2011 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2012 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2017 if (OldProtect
!= NewProtect
)
2019 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2021 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2022 ULONG Protect
= NewProtect
;
2025 * If we doing COW for this segment then check if the page is
2028 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2034 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2035 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2036 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2037 Page
= MmGetPfnForProcess(Process
, Address
);
2039 Protect
= PAGE_READONLY
;
2040 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2041 IS_SWAP_FROM_SSE(Entry
) ||
2042 PFN_FROM_SSE(Entry
) != Page
)
2044 Protect
= NewProtect
;
2048 if (MmIsPagePresent(Process
, Address
))
2050 MmSetPageProtect(Process
, Address
,
2059 MmProtectSectionView(PMM_AVL_TABLE AddressSpace
,
2060 PMEMORY_AREA MemoryArea
,
2068 ULONG_PTR MaxLength
;
2070 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2071 if (Length
> MaxLength
)
2074 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2075 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2077 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2078 Region
->Protect
!= Protect
)
2080 return STATUS_INVALID_PAGE_PROTECTION
;
2083 *OldProtect
= Region
->Protect
;
2084 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2085 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2086 BaseAddress
, Length
, Region
->Type
, Protect
,
2087 MmAlterViewAttributes
);
2093 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2095 PMEMORY_BASIC_INFORMATION Info
,
2096 PSIZE_T ResultLength
)
2099 PVOID RegionBaseAddress
;
2100 PROS_SECTION_OBJECT Section
;
2101 PMM_SECTION_SEGMENT Segment
;
2103 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2104 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2105 Address
, &RegionBaseAddress
);
2108 return STATUS_UNSUCCESSFUL
;
2111 Section
= MemoryArea
->Data
.SectionData
.Section
;
2112 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2114 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2115 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2116 Info
->Type
= MEM_IMAGE
;
2120 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2121 Info
->Type
= MEM_MAPPED
;
2123 Info
->BaseAddress
= RegionBaseAddress
;
2124 Info
->AllocationProtect
= MemoryArea
->Protect
;
2125 Info
->RegionSize
= Region
->Length
;
2126 Info
->State
= MEM_COMMIT
;
2127 Info
->Protect
= Region
->Protect
;
2129 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2130 return(STATUS_SUCCESS
);
2135 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2140 ULONG SavedSwapEntry
;
2145 Length
= PAGE_ROUND_UP(Segment
->Length
);
2146 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2148 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2151 if (IS_SWAP_FROM_SSE(Entry
))
2153 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2157 Page
= PFN_FROM_SSE(Entry
);
2158 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2159 if (SavedSwapEntry
!= 0)
2161 MmSetSavedSwapEntryPage(Page
, 0);
2162 MmFreeSwapPage(SavedSwapEntry
);
2164 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2166 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2172 MmpDeleteSection(PVOID ObjectBody
)
2174 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2176 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2177 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2182 PMM_SECTION_SEGMENT SectionSegments
;
2185 * NOTE: Section->ImageSection can be NULL for short time
2186 * during the section creating. If we fail for some reason
2187 * until the image section is properly initialized we shouldn't
2188 * process further here.
2190 if (Section
->ImageSection
== NULL
)
2193 SectionSegments
= Section
->ImageSection
->Segments
;
2194 NrSegments
= Section
->ImageSection
->NrSegments
;
2196 for (i
= 0; i
< NrSegments
; i
++)
2198 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2200 MmLockSectionSegment(&SectionSegments
[i
]);
2202 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2203 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2207 MmpFreePageFileSegment(&SectionSegments
[i
]);
2209 MmUnlockSectionSegment(&SectionSegments
[i
]);
2216 * NOTE: Section->Segment can be NULL for short time
2217 * during the section creating.
2219 if (Section
->Segment
== NULL
)
2222 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2224 MmpFreePageFileSegment(Section
->Segment
);
2225 MmFreePageTablesSectionSegment(Section
->Segment
);
2226 ExFreePool(Section
->Segment
);
2227 Section
->Segment
= NULL
;
2231 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2234 if (Section
->FileObject
!= NULL
)
2236 CcRosDereferenceCache(Section
->FileObject
);
2237 ObDereferenceObject(Section
->FileObject
);
2238 Section
->FileObject
= NULL
;
2243 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2245 IN ACCESS_MASK GrantedAccess
,
2246 IN ULONG ProcessHandleCount
,
2247 IN ULONG SystemHandleCount
)
2249 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2250 Object
, ProcessHandleCount
);
2256 MmCreatePhysicalMemorySection(VOID
)
2258 PROS_SECTION_OBJECT PhysSection
;
2260 OBJECT_ATTRIBUTES Obj
;
2261 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2262 LARGE_INTEGER SectionSize
;
2266 * Create the section mapping physical memory
2268 SectionSize
.QuadPart
= 0xFFFFFFFF;
2269 InitializeObjectAttributes(&Obj
,
2274 Status
= MmCreateSection((PVOID
)&PhysSection
,
2278 PAGE_EXECUTE_READWRITE
,
2282 if (!NT_SUCCESS(Status
))
2284 DPRINT1("Failed to create PhysicalMemory section\n");
2285 KeBugCheck(MEMORY_MANAGEMENT
);
2287 Status
= ObInsertObject(PhysSection
,
2293 if (!NT_SUCCESS(Status
))
2295 ObDereferenceObject(PhysSection
);
2297 ObCloseHandle(Handle
, KernelMode
);
2298 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2299 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2301 return(STATUS_SUCCESS
);
2307 MmInitSectionImplementation(VOID
)
2309 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2310 UNICODE_STRING Name
;
2312 DPRINT("Creating Section Object Type\n");
2314 /* Initialize the Section object type */
2315 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2316 RtlInitUnicodeString(&Name
, L
"Section");
2317 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2318 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2319 ObjectTypeInitializer
.PoolType
= PagedPool
;
2320 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2321 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2322 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2323 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2324 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2325 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2327 return(STATUS_SUCCESS
);
2332 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2333 ACCESS_MASK DesiredAccess
,
2334 POBJECT_ATTRIBUTES ObjectAttributes
,
2335 PLARGE_INTEGER UMaximumSize
,
2336 ULONG SectionPageProtection
,
2337 ULONG AllocationAttributes
)
2339 * Create a section which is backed by the pagefile
2342 LARGE_INTEGER MaximumSize
;
2343 PROS_SECTION_OBJECT Section
;
2344 PMM_SECTION_SEGMENT Segment
;
2347 if (UMaximumSize
== NULL
)
2349 return(STATUS_UNSUCCESSFUL
);
2351 MaximumSize
= *UMaximumSize
;
2354 * Create the section
2356 Status
= ObCreateObject(ExGetPreviousMode(),
2357 MmSectionObjectType
,
2359 ExGetPreviousMode(),
2361 sizeof(ROS_SECTION_OBJECT
),
2364 (PVOID
*)(PVOID
)&Section
);
2365 if (!NT_SUCCESS(Status
))
2373 Section
->SectionPageProtection
= SectionPageProtection
;
2374 Section
->AllocationAttributes
= AllocationAttributes
;
2375 Section
->Segment
= NULL
;
2376 Section
->FileObject
= NULL
;
2377 Section
->MaximumSize
= MaximumSize
;
2378 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2379 TAG_MM_SECTION_SEGMENT
);
2380 if (Segment
== NULL
)
2382 ObDereferenceObject(Section
);
2383 return(STATUS_NO_MEMORY
);
2385 Section
->Segment
= Segment
;
2386 Segment
->ReferenceCount
= 1;
2387 ExInitializeFastMutex(&Segment
->Lock
);
2388 Segment
->FileOffset
= 0;
2389 Segment
->Protection
= SectionPageProtection
;
2390 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2391 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2392 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2393 Segment
->WriteCopy
= FALSE
;
2394 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2395 Segment
->VirtualAddress
= 0;
2396 Segment
->Characteristics
= 0;
2397 *SectionObject
= Section
;
2398 return(STATUS_SUCCESS
);
2404 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2405 ACCESS_MASK DesiredAccess
,
2406 POBJECT_ATTRIBUTES ObjectAttributes
,
2407 PLARGE_INTEGER UMaximumSize
,
2408 ULONG SectionPageProtection
,
2409 ULONG AllocationAttributes
,
2412 * Create a section backed by a data file
2415 PROS_SECTION_OBJECT Section
;
2417 LARGE_INTEGER MaximumSize
;
2418 PFILE_OBJECT FileObject
;
2419 PMM_SECTION_SEGMENT Segment
;
2421 IO_STATUS_BLOCK Iosb
;
2422 LARGE_INTEGER Offset
;
2424 FILE_STANDARD_INFORMATION FileInfo
;
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 Iosb
.Information
= Length
;
2490 if (!NT_SUCCESS(Status
))
2492 ObDereferenceObject(Section
);
2493 ObDereferenceObject(FileObject
);
2498 * FIXME: Revise this once a locking order for file size changes is
2501 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2503 MaximumSize
= *UMaximumSize
;
2507 MaximumSize
= FileInfo
.EndOfFile
;
2508 /* Mapping zero-sized files isn't allowed. */
2509 if (MaximumSize
.QuadPart
== 0)
2511 ObDereferenceObject(Section
);
2512 ObDereferenceObject(FileObject
);
2513 return STATUS_FILE_INVALID
;
2517 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2519 Status
= IoSetInformation(FileObject
,
2520 FileAllocationInformation
,
2521 sizeof(LARGE_INTEGER
),
2523 if (!NT_SUCCESS(Status
))
2525 ObDereferenceObject(Section
);
2526 ObDereferenceObject(FileObject
);
2527 return(STATUS_SECTION_NOT_EXTENDED
);
2531 if (FileObject
->SectionObjectPointer
== NULL
||
2532 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2535 * Read a bit so caching is initiated for the file object.
2536 * This is only needed because MiReadPage currently cannot
2537 * handle non-cached streams.
2539 Offset
.QuadPart
= 0;
2540 Status
= ZwReadFile(FileHandle
,
2549 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2551 ObDereferenceObject(Section
);
2552 ObDereferenceObject(FileObject
);
2555 if (FileObject
->SectionObjectPointer
== NULL
||
2556 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2558 /* FIXME: handle this situation */
2559 ObDereferenceObject(Section
);
2560 ObDereferenceObject(FileObject
);
2561 return STATUS_INVALID_PARAMETER
;
2568 Status
= MmspWaitForFileLock(FileObject
);
2569 if (Status
!= STATUS_SUCCESS
)
2571 ObDereferenceObject(Section
);
2572 ObDereferenceObject(FileObject
);
2577 * If this file hasn't been mapped as a data file before then allocate a
2578 * section segment to describe the data file mapping
2580 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2582 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2583 TAG_MM_SECTION_SEGMENT
);
2584 if (Segment
== NULL
)
2586 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2587 ObDereferenceObject(Section
);
2588 ObDereferenceObject(FileObject
);
2589 return(STATUS_NO_MEMORY
);
2591 Section
->Segment
= Segment
;
2592 Segment
->ReferenceCount
= 1;
2593 ExInitializeFastMutex(&Segment
->Lock
);
2595 * Set the lock before assigning the segment to the file object
2597 ExAcquireFastMutex(&Segment
->Lock
);
2598 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2600 Segment
->FileOffset
= 0;
2601 Segment
->Protection
= SectionPageProtection
;
2602 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2603 Segment
->Characteristics
= 0;
2604 Segment
->WriteCopy
= FALSE
;
2605 if (AllocationAttributes
& SEC_RESERVE
)
2607 Segment
->Length
= Segment
->RawLength
= 0;
2611 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2612 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2614 Segment
->VirtualAddress
= 0;
2615 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2620 * If the file is already mapped as a data file then we may need
2624 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2626 Section
->Segment
= Segment
;
2627 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2628 MmLockSectionSegment(Segment
);
2630 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2631 !(AllocationAttributes
& SEC_RESERVE
))
2633 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2634 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2637 MmUnlockSectionSegment(Segment
);
2638 Section
->FileObject
= FileObject
;
2639 Section
->MaximumSize
= MaximumSize
;
2640 CcRosReferenceCache(FileObject
);
2641 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2642 *SectionObject
= Section
;
2643 return(STATUS_SUCCESS
);
2647 TODO: not that great (declaring loaders statically, having to declare all of
2648 them, having to keep them extern, etc.), will fix in the future
2650 extern NTSTATUS NTAPI PeFmtCreateSection
2652 IN CONST VOID
* FileHeader
,
2653 IN SIZE_T FileHeaderSize
,
2655 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2657 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2658 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2661 extern NTSTATUS NTAPI ElfFmtCreateSection
2663 IN CONST VOID
* FileHeader
,
2664 IN SIZE_T FileHeaderSize
,
2666 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2668 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2669 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2672 /* TODO: this is a standard DDK/PSDK macro */
2673 #ifndef RTL_NUMBER_OF
2674 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2677 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2688 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2690 SIZE_T SizeOfSegments
;
2691 PMM_SECTION_SEGMENT Segments
;
2693 /* TODO: check for integer overflow */
2694 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2696 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2698 TAG_MM_SECTION_SEGMENT
);
2701 RtlZeroMemory(Segments
, SizeOfSegments
);
2709 ExeFmtpReadFile(IN PVOID File
,
2710 IN PLARGE_INTEGER Offset
,
2713 OUT PVOID
* AllocBase
,
2714 OUT PULONG ReadSize
)
2717 LARGE_INTEGER FileOffset
;
2719 ULONG OffsetAdjustment
;
2724 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2728 KeBugCheck(MEMORY_MANAGEMENT
);
2731 FileOffset
= *Offset
;
2733 /* Negative/special offset: it cannot be used in this context */
2734 if(FileOffset
.u
.HighPart
< 0)
2736 KeBugCheck(MEMORY_MANAGEMENT
);
2739 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2740 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2741 FileOffset
.u
.LowPart
= AdjustOffset
;
2743 BufferSize
= Length
+ OffsetAdjustment
;
2744 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2747 * It's ok to use paged pool, because this is a temporary buffer only used in
2748 * the loading of executables. The assumption is that MmCreateSection is
2749 * always called at low IRQLs and that these buffers don't survive a brief
2750 * initialization phase
2752 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2754 TAG('M', 'm', 'X', 'r'));
2759 Status
= MmspPageRead(File
,
2766 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2767 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2768 * to initialize internal state is even worse. Our cache manager is in need of
2772 IO_STATUS_BLOCK Iosb
;
2774 Status
= ZwReadFile(File
,
2784 if(NT_SUCCESS(Status
))
2786 UsedSize
= Iosb
.Information
;
2791 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2793 Status
= STATUS_IN_PAGE_ERROR
;
2794 ASSERT(!NT_SUCCESS(Status
));
2797 if(NT_SUCCESS(Status
))
2799 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2800 *AllocBase
= Buffer
;
2801 *ReadSize
= UsedSize
- OffsetAdjustment
;
2805 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2812 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2813 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2814 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2819 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2823 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2825 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2826 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2833 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2837 MmspAssertSegmentsSorted(ImageSectionObject
);
2839 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2841 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2845 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2846 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2847 ImageSectionObject
->Segments
[i
- 1].Length
));
2855 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2859 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2861 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2862 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2870 MmspCompareSegments(const void * x
,
2873 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2874 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2877 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2878 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2882 * Ensures an image section's segments are sorted in memory
2887 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2890 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2892 MmspAssertSegmentsSorted(ImageSectionObject
);
2896 qsort(ImageSectionObject
->Segments
,
2897 ImageSectionObject
->NrSegments
,
2898 sizeof(ImageSectionObject
->Segments
[0]),
2899 MmspCompareSegments
);
2905 * Ensures an image section's segments don't overlap in memory and don't have
2906 * gaps and don't have a null size. We let them map to overlapping file regions,
2907 * though - that's not necessarily an error
2912 MmspCheckSegmentBounds
2914 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2920 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2922 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2926 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2928 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2930 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2938 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2939 * page could be OK (Windows seems to be OK with them), and larger gaps
2940 * could lead to image sections spanning several discontiguous regions
2941 * (NtMapViewOfSection could then refuse to map them, and they could
2942 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2944 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2945 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2946 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2957 * Merges and pads an image section's segments until they all are page-aligned
2958 * and have a size that is a multiple of the page size
2963 MmspPageAlignSegments
2965 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2971 BOOLEAN Initialized
;
2972 PMM_SECTION_SEGMENT EffectiveSegment
;
2974 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2976 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2980 Initialized
= FALSE
;
2982 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2984 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2987 * The first segment requires special handling
2991 ULONG_PTR VirtualAddress
;
2992 ULONG_PTR VirtualOffset
;
2994 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2996 /* Round down the virtual address to the nearest page */
2997 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2999 /* Round up the virtual size to the nearest page */
3000 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3001 EffectiveSegment
->VirtualAddress
;
3003 /* Adjust the raw address and size */
3004 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3006 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3012 * Garbage in, garbage out: unaligned base addresses make the file
3013 * offset point in curious and odd places, but that's what we were
3016 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3017 EffectiveSegment
->RawLength
+= VirtualOffset
;
3021 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3022 ULONG_PTR EndOfEffectiveSegment
;
3024 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3025 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3028 * The current segment begins exactly where the current effective
3029 * segment ended, therefore beginning a new effective segment
3031 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3034 ASSERT(LastSegment
<= i
);
3035 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3037 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3039 if (LastSegment
!= i
)
3042 * Copy the current segment. If necessary, the effective segment
3043 * will be expanded later
3045 *EffectiveSegment
= *Segment
;
3049 * Page-align the virtual size. We know for sure the virtual address
3052 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3053 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3056 * The current segment is still part of the current effective segment:
3057 * extend the effective segment to reflect this
3059 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3061 static const ULONG FlagsToProtection
[16] =
3069 PAGE_EXECUTE_READWRITE
,
3070 PAGE_EXECUTE_READWRITE
,
3075 PAGE_EXECUTE_WRITECOPY
,
3076 PAGE_EXECUTE_WRITECOPY
,
3077 PAGE_EXECUTE_WRITECOPY
,
3078 PAGE_EXECUTE_WRITECOPY
3081 unsigned ProtectionFlags
;
3084 * Extend the file size
3087 /* Unaligned segments must be contiguous within the file */
3088 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3089 EffectiveSegment
->RawLength
))
3094 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3097 * Extend the virtual size
3099 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3101 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3102 EffectiveSegment
->VirtualAddress
;
3105 * Merge the protection
3107 EffectiveSegment
->Protection
|= Segment
->Protection
;
3109 /* Clean up redundance */
3110 ProtectionFlags
= 0;
3112 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3113 ProtectionFlags
|= 1 << 0;
3115 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3116 ProtectionFlags
|= 1 << 1;
3118 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3119 ProtectionFlags
|= 1 << 2;
3121 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3122 ProtectionFlags
|= 1 << 3;
3124 ASSERT(ProtectionFlags
< 16);
3125 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3127 /* If a segment was required to be shared and cannot, fail */
3128 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3129 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3135 * We assume no holes between segments at this point
3139 KeBugCheck(MEMORY_MANAGEMENT
);
3143 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3149 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3150 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3152 LARGE_INTEGER Offset
;
3154 PVOID FileHeaderBuffer
;
3155 ULONG FileHeaderSize
;
3157 ULONG OldNrSegments
;
3162 * Read the beginning of the file (2 pages). Should be enough to contain
3163 * all (or most) of the headers
3165 Offset
.QuadPart
= 0;
3167 /* FIXME: use FileObject instead of FileHandle */
3168 Status
= ExeFmtpReadFile (FileHandle
,
3175 if (!NT_SUCCESS(Status
))
3178 if (FileHeaderSize
== 0)
3180 ExFreePool(FileHeaderBuffer
);
3181 return STATUS_UNSUCCESSFUL
;
3185 * Look for a loader that can handle this executable
3187 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3189 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3192 /* FIXME: use FileObject instead of FileHandle */
3193 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3199 ExeFmtpAllocateSegments
);
3201 if (!NT_SUCCESS(Status
))
3203 if (ImageSectionObject
->Segments
)
3205 ExFreePool(ImageSectionObject
->Segments
);
3206 ImageSectionObject
->Segments
= NULL
;
3210 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3214 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3217 * No loader handled the format
3219 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3221 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3222 ASSERT(!NT_SUCCESS(Status
));
3225 if (!NT_SUCCESS(Status
))
3228 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3233 /* FIXME? are these values platform-dependent? */
3234 if(ImageSectionObject
->StackReserve
== 0)
3235 ImageSectionObject
->StackReserve
= 0x40000;
3237 if(ImageSectionObject
->StackCommit
== 0)
3238 ImageSectionObject
->StackCommit
= 0x1000;
3240 if(ImageSectionObject
->ImageBase
== 0)
3242 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3243 ImageSectionObject
->ImageBase
= 0x10000000;
3245 ImageSectionObject
->ImageBase
= 0x00400000;
3249 * And now the fun part: fixing the segments
3252 /* Sort them by virtual address */
3253 MmspSortSegments(ImageSectionObject
, Flags
);
3255 /* Ensure they don't overlap in memory */
3256 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3257 return STATUS_INVALID_IMAGE_FORMAT
;
3259 /* Ensure they are aligned */
3260 OldNrSegments
= ImageSectionObject
->NrSegments
;
3262 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3263 return STATUS_INVALID_IMAGE_FORMAT
;
3265 /* Trim them if the alignment phase merged some of them */
3266 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3268 PMM_SECTION_SEGMENT Segments
;
3269 SIZE_T SizeOfSegments
;
3271 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3273 Segments
= ExAllocatePoolWithTag(PagedPool
,
3275 TAG_MM_SECTION_SEGMENT
);
3277 if (Segments
== NULL
)
3278 return STATUS_INSUFFICIENT_RESOURCES
;
3280 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3281 ExFreePool(ImageSectionObject
->Segments
);
3282 ImageSectionObject
->Segments
= Segments
;
3285 /* And finish their initialization */
3286 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3288 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3289 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3291 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3292 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3295 ASSERT(NT_SUCCESS(Status
));
3300 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3301 ACCESS_MASK DesiredAccess
,
3302 POBJECT_ATTRIBUTES ObjectAttributes
,
3303 PLARGE_INTEGER UMaximumSize
,
3304 ULONG SectionPageProtection
,
3305 ULONG AllocationAttributes
,
3308 PROS_SECTION_OBJECT Section
;
3310 PFILE_OBJECT FileObject
;
3311 PMM_SECTION_SEGMENT SectionSegments
;
3312 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3314 ULONG FileAccess
= 0;
3317 * Specifying a maximum size is meaningless for an image section
3319 if (UMaximumSize
!= NULL
)
3321 return(STATUS_INVALID_PARAMETER_4
);
3325 * Check file access required
3327 if (SectionPageProtection
& PAGE_READWRITE
||
3328 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3330 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3334 FileAccess
= FILE_READ_DATA
;
3338 * Reference the file handle
3340 Status
= ObReferenceObjectByHandle(FileHandle
,
3343 ExGetPreviousMode(),
3344 (PVOID
*)(PVOID
)&FileObject
,
3347 if (!NT_SUCCESS(Status
))
3353 * Create the section
3355 Status
= ObCreateObject (ExGetPreviousMode(),
3356 MmSectionObjectType
,
3358 ExGetPreviousMode(),
3360 sizeof(ROS_SECTION_OBJECT
),
3363 (PVOID
*)(PVOID
)&Section
);
3364 if (!NT_SUCCESS(Status
))
3366 ObDereferenceObject(FileObject
);
3373 Section
->SectionPageProtection
= SectionPageProtection
;
3374 Section
->AllocationAttributes
= AllocationAttributes
;
3377 * Initialized caching for this file object if previously caching
3378 * was initialized for the same on disk file
3380 Status
= CcTryToInitializeFileCache(FileObject
);
3382 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3384 NTSTATUS StatusExeFmt
;
3386 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3387 if (ImageSectionObject
== NULL
)
3389 ObDereferenceObject(FileObject
);
3390 ObDereferenceObject(Section
);
3391 return(STATUS_NO_MEMORY
);
3394 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3396 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3398 if (!NT_SUCCESS(StatusExeFmt
))
3400 if(ImageSectionObject
->Segments
!= NULL
)
3401 ExFreePool(ImageSectionObject
->Segments
);
3403 ExFreePool(ImageSectionObject
);
3404 ObDereferenceObject(Section
);
3405 ObDereferenceObject(FileObject
);
3406 return(StatusExeFmt
);
3409 Section
->ImageSection
= ImageSectionObject
;
3410 ASSERT(ImageSectionObject
->Segments
);
3415 Status
= MmspWaitForFileLock(FileObject
);
3416 if (!NT_SUCCESS(Status
))
3418 ExFreePool(ImageSectionObject
->Segments
);
3419 ExFreePool(ImageSectionObject
);
3420 ObDereferenceObject(Section
);
3421 ObDereferenceObject(FileObject
);
3425 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3426 ImageSectionObject
, NULL
))
3429 * An other thread has initialized the same image in the background
3431 ExFreePool(ImageSectionObject
->Segments
);
3432 ExFreePool(ImageSectionObject
);
3433 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3434 Section
->ImageSection
= ImageSectionObject
;
3435 SectionSegments
= ImageSectionObject
->Segments
;
3437 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3439 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3443 Status
= StatusExeFmt
;
3450 Status
= MmspWaitForFileLock(FileObject
);
3451 if (Status
!= STATUS_SUCCESS
)
3453 ObDereferenceObject(Section
);
3454 ObDereferenceObject(FileObject
);
3458 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3459 Section
->ImageSection
= ImageSectionObject
;
3460 SectionSegments
= ImageSectionObject
->Segments
;
3463 * Otherwise just reference all the section segments
3465 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3467 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3470 Status
= STATUS_SUCCESS
;
3472 Section
->FileObject
= FileObject
;
3473 CcRosReferenceCache(FileObject
);
3474 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3475 *SectionObject
= Section
;
3483 NtCreateSection (OUT PHANDLE SectionHandle
,
3484 IN ACCESS_MASK DesiredAccess
,
3485 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3486 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3487 IN ULONG SectionPageProtection OPTIONAL
,
3488 IN ULONG AllocationAttributes
,
3489 IN HANDLE FileHandle OPTIONAL
)
3491 LARGE_INTEGER SafeMaximumSize
;
3492 PVOID SectionObject
;
3493 KPROCESSOR_MODE PreviousMode
;
3494 NTSTATUS Status
= STATUS_SUCCESS
;
3496 PreviousMode
= ExGetPreviousMode();
3498 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3502 /* make a copy on the stack */
3503 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3504 MaximumSize
= &SafeMaximumSize
;
3506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3508 Status
= _SEH2_GetExceptionCode();
3512 if(!NT_SUCCESS(Status
))
3518 Status
= MmCreateSection(&SectionObject
,
3522 SectionPageProtection
,
3523 AllocationAttributes
,
3526 if (NT_SUCCESS(Status
))
3528 Status
= ObInsertObject ((PVOID
)SectionObject
,
3540 /**********************************************************************
3558 NtOpenSection(PHANDLE SectionHandle
,
3559 ACCESS_MASK DesiredAccess
,
3560 POBJECT_ATTRIBUTES ObjectAttributes
)
3563 KPROCESSOR_MODE PreviousMode
;
3564 NTSTATUS Status
= STATUS_SUCCESS
;
3566 PreviousMode
= ExGetPreviousMode();
3568 if(PreviousMode
!= KernelMode
)
3572 ProbeForWriteHandle(SectionHandle
);
3574 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3576 Status
= _SEH2_GetExceptionCode();
3580 if(!NT_SUCCESS(Status
))
3586 Status
= ObOpenObjectByName(ObjectAttributes
,
3587 MmSectionObjectType
,
3594 if(NT_SUCCESS(Status
))
3598 *SectionHandle
= hSection
;
3600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3602 Status
= _SEH2_GetExceptionCode();
3611 MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3612 PROS_SECTION_OBJECT Section
,
3613 PMM_SECTION_SEGMENT Segment
,
3618 ULONG AllocationType
)
3622 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3624 BoundaryAddressMultiple
.QuadPart
= 0;
3626 Status
= MmCreateMemoryArea(AddressSpace
,
3627 MEMORY_AREA_SECTION_VIEW
,
3634 BoundaryAddressMultiple
);
3635 if (!NT_SUCCESS(Status
))
3637 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3638 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3642 ObReferenceObject((PVOID
)Section
);
3644 MArea
->Data
.SectionData
.Segment
= Segment
;
3645 MArea
->Data
.SectionData
.Section
= Section
;
3646 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3647 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3648 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3649 ViewSize
, 0, Protect
);
3651 return(STATUS_SUCCESS
);
3655 /**********************************************************************
3657 * NtMapViewOfSection
3660 * Maps a view of a section into the virtual address space of a
3665 * Handle of the section.
3668 * Handle of the process.
3671 * Desired base address (or NULL) on entry;
3672 * Actual base address of the view on exit.
3675 * Number of high order address bits that must be zero.
3678 * Size in bytes of the initially committed section of
3682 * Offset in bytes from the beginning of the section
3683 * to the beginning of the view.
3686 * Desired length of map (or zero to map all) on entry
3687 * Actual length mapped on exit.
3689 * InheritDisposition
3690 * Specified how the view is to be shared with
3694 * Type of allocation for the pages.
3697 * Protection for the committed region of the view.
3705 NtMapViewOfSection(IN HANDLE SectionHandle
,
3706 IN HANDLE ProcessHandle
,
3707 IN OUT PVOID
* BaseAddress OPTIONAL
,
3708 IN ULONG_PTR ZeroBits OPTIONAL
,
3709 IN SIZE_T CommitSize
,
3710 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3711 IN OUT PSIZE_T ViewSize
,
3712 IN SECTION_INHERIT InheritDisposition
,
3713 IN ULONG AllocationType OPTIONAL
,
3716 PVOID SafeBaseAddress
;
3717 LARGE_INTEGER SafeSectionOffset
;
3718 SIZE_T SafeViewSize
;
3719 PROS_SECTION_OBJECT Section
;
3721 KPROCESSOR_MODE PreviousMode
;
3722 PMM_AVL_TABLE AddressSpace
;
3723 NTSTATUS Status
= STATUS_SUCCESS
;
3727 * Check the protection
3729 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3731 return STATUS_INVALID_PARAMETER_10
;
3734 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3735 if (tmpProtect
!= PAGE_NOACCESS
&&
3736 tmpProtect
!= PAGE_READONLY
&&
3737 tmpProtect
!= PAGE_READWRITE
&&
3738 tmpProtect
!= PAGE_WRITECOPY
&&
3739 tmpProtect
!= PAGE_EXECUTE
&&
3740 tmpProtect
!= PAGE_EXECUTE_READ
&&
3741 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3742 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3744 return STATUS_INVALID_PAGE_PROTECTION
;
3747 PreviousMode
= ExGetPreviousMode();
3749 if(PreviousMode
!= KernelMode
)
3751 SafeBaseAddress
= NULL
;
3752 SafeSectionOffset
.QuadPart
= 0;
3757 if(BaseAddress
!= NULL
)
3759 ProbeForWritePointer(BaseAddress
);
3760 SafeBaseAddress
= *BaseAddress
;
3762 if(SectionOffset
!= NULL
)
3764 ProbeForWriteLargeInteger(SectionOffset
);
3765 SafeSectionOffset
= *SectionOffset
;
3767 ProbeForWriteSize_t(ViewSize
);
3768 SafeViewSize
= *ViewSize
;
3770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3772 Status
= _SEH2_GetExceptionCode();
3776 if(!NT_SUCCESS(Status
))
3783 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3784 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3785 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3788 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3790 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3791 PROCESS_VM_OPERATION
,
3794 (PVOID
*)(PVOID
)&Process
,
3796 if (!NT_SUCCESS(Status
))
3801 AddressSpace
= &Process
->VadRoot
;
3803 Status
= ObReferenceObjectByHandle(SectionHandle
,
3805 MmSectionObjectType
,
3807 (PVOID
*)(PVOID
)&Section
,
3809 if (!(NT_SUCCESS(Status
)))
3811 DPRINT("ObReference failed rc=%x\n",Status
);
3812 ObDereferenceObject(Process
);
3816 Status
= MmMapViewOfSection(Section
,
3818 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3821 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3822 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3827 /* Check if this is an image for the current process */
3828 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3829 (Process
== PsGetCurrentProcess()) &&
3830 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3832 /* Notify the debugger */
3833 DbgkMapViewOfSection(Section
,
3835 SafeSectionOffset
.LowPart
,
3839 ObDereferenceObject(Section
);
3840 ObDereferenceObject(Process
);
3842 if(NT_SUCCESS(Status
))
3844 /* copy parameters back to the caller */
3847 if(BaseAddress
!= NULL
)
3849 *BaseAddress
= SafeBaseAddress
;
3851 if(SectionOffset
!= NULL
)
3853 *SectionOffset
= SafeSectionOffset
;
3855 if(ViewSize
!= NULL
)
3857 *ViewSize
= SafeViewSize
;
3860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3862 Status
= _SEH2_GetExceptionCode();
3871 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3872 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3875 PFILE_OBJECT FileObject
;
3878 SWAPENTRY SavedSwapEntry
;
3881 PROS_SECTION_OBJECT Section
;
3882 PMM_SECTION_SEGMENT Segment
;
3883 PMM_AVL_TABLE AddressSpace
;
3886 AddressSpace
= (PMM_AVL_TABLE
)Context
;
3887 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3889 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3891 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3892 MemoryArea
->Data
.SectionData
.ViewOffset
;
3894 Section
= MemoryArea
->Data
.SectionData
.Section
;
3895 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3897 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3901 MmUnlockSectionSegment(Segment
);
3902 MmUnlockAddressSpace(AddressSpace
);
3904 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3905 if (Status
!= STATUS_SUCCESS
)
3907 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3908 KeBugCheck(MEMORY_MANAGEMENT
);
3911 MmLockAddressSpace(AddressSpace
);
3912 MmLockSectionSegment(Segment
);
3913 MmspCompleteAndReleasePageOp(PageOp
);
3914 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3917 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3920 * For a dirty, datafile, non-private page mark it as dirty in the
3923 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3925 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3927 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3928 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3929 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3930 ASSERT(SwapEntry
== 0);
3939 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3941 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3942 KeBugCheck(MEMORY_MANAGEMENT
);
3944 MmFreeSwapPage(SwapEntry
);
3948 if (IS_SWAP_FROM_SSE(Entry
) ||
3949 Page
!= PFN_FROM_SSE(Entry
))
3954 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3956 DPRINT1("Found a private page in a pagefile section.\n");
3957 KeBugCheck(MEMORY_MANAGEMENT
);
3960 * Just dereference private pages
3962 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3963 if (SavedSwapEntry
!= 0)
3965 MmFreeSwapPage(SavedSwapEntry
);
3966 MmSetSavedSwapEntryPage(Page
, 0);
3968 MmDeleteRmap(Page
, Process
, Address
);
3969 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3973 MmDeleteRmap(Page
, Process
, Address
);
3974 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3980 MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3984 PMEMORY_AREA MemoryArea
;
3985 PROS_SECTION_OBJECT Section
;
3986 PMM_SECTION_SEGMENT Segment
;
3987 PLIST_ENTRY CurrentEntry
;
3988 PMM_REGION CurrentRegion
;
3989 PLIST_ENTRY RegionListHead
;
3991 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3993 if (MemoryArea
== NULL
)
3995 return(STATUS_UNSUCCESSFUL
);
3998 MemoryArea
->DeleteInProgress
= TRUE
;
3999 Section
= MemoryArea
->Data
.SectionData
.Section
;
4000 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4002 MmLockSectionSegment(Segment
);
4004 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4005 while (!IsListEmpty(RegionListHead
))
4007 CurrentEntry
= RemoveHeadList(RegionListHead
);
4008 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4009 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4012 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4014 Status
= MmFreeMemoryArea(AddressSpace
,
4021 Status
= MmFreeMemoryArea(AddressSpace
,
4026 MmUnlockSectionSegment(Segment
);
4027 ObDereferenceObject(Section
);
4028 return(STATUS_SUCCESS
);
4035 MmUnmapViewOfSection(PEPROCESS Process
,
4039 PMEMORY_AREA MemoryArea
;
4040 PMM_AVL_TABLE AddressSpace
;
4041 PROS_SECTION_OBJECT Section
;
4044 PVOID ImageBaseAddress
= 0;
4046 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4047 Process
, BaseAddress
);
4051 AddressSpace
= &Process
->VadRoot
;
4053 MmLockAddressSpace(AddressSpace
);
4054 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4056 if (MemoryArea
== NULL
||
4057 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4058 MemoryArea
->DeleteInProgress
)
4060 MmUnlockAddressSpace(AddressSpace
);
4061 return STATUS_NOT_MAPPED_VIEW
;
4064 MemoryArea
->DeleteInProgress
= TRUE
;
4066 while (MemoryArea
->PageOpCount
)
4068 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4072 Offset
-= PAGE_SIZE
;
4073 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4074 MemoryArea
->Data
.SectionData
.Segment
,
4075 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4078 MmUnlockAddressSpace(AddressSpace
);
4079 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4080 if (Status
!= STATUS_SUCCESS
)
4082 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4083 KeBugCheck(MEMORY_MANAGEMENT
);
4085 MmLockAddressSpace(AddressSpace
);
4086 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4088 if (MemoryArea
== NULL
||
4089 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4091 MmUnlockAddressSpace(AddressSpace
);
4092 return STATUS_NOT_MAPPED_VIEW
;
4099 Section
= MemoryArea
->Data
.SectionData
.Section
;
4101 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4105 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4106 PMM_SECTION_SEGMENT SectionSegments
;
4107 PMM_SECTION_SEGMENT Segment
;
4109 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4110 ImageSectionObject
= Section
->ImageSection
;
4111 SectionSegments
= ImageSectionObject
->Segments
;
4112 NrSegments
= ImageSectionObject
->NrSegments
;
4114 /* Search for the current segment within the section segments
4115 * and calculate the image base address */
4116 for (i
= 0; i
< NrSegments
; i
++)
4118 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4120 if (Segment
== &SectionSegments
[i
])
4122 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4127 if (i
>= NrSegments
)
4129 KeBugCheck(MEMORY_MANAGEMENT
);
4132 for (i
= 0; i
< NrSegments
; i
++)
4134 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4136 PVOID SBaseAddress
= (PVOID
)
4137 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4139 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4145 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4148 /* Notify debugger */
4149 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4151 MmUnlockAddressSpace(AddressSpace
);
4152 return(STATUS_SUCCESS
);
4155 /**********************************************************************
4157 * NtUnmapViewOfSection
4172 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4176 KPROCESSOR_MODE PreviousMode
;
4179 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4180 ProcessHandle
, BaseAddress
);
4182 PreviousMode
= ExGetPreviousMode();
4184 DPRINT("Referencing process\n");
4185 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4186 PROCESS_VM_OPERATION
,
4189 (PVOID
*)(PVOID
)&Process
,
4191 if (!NT_SUCCESS(Status
))
4193 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4197 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4199 ObDereferenceObject(Process
);
4206 * Queries the information of a section object.
4208 * @param SectionHandle
4209 * Handle to the section object. It must be opened with SECTION_QUERY
4211 * @param SectionInformationClass
4212 * Index to a certain information structure. Can be either
4213 * SectionBasicInformation or SectionImageInformation. The latter
4214 * is valid only for sections that were created with the SEC_IMAGE
4216 * @param SectionInformation
4217 * Caller supplies storage for resulting information.
4219 * Size of the supplied storage.
4220 * @param ResultLength
4228 NtQuerySection(IN HANDLE SectionHandle
,
4229 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4230 OUT PVOID SectionInformation
,
4231 IN SIZE_T SectionInformationLength
,
4232 OUT PSIZE_T ResultLength OPTIONAL
)
4234 PROS_SECTION_OBJECT Section
;
4235 KPROCESSOR_MODE PreviousMode
;
4236 NTSTATUS Status
= STATUS_SUCCESS
;
4238 PreviousMode
= ExGetPreviousMode();
4240 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4242 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4244 SectionInformationLength
,
4249 if(!NT_SUCCESS(Status
))
4251 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4255 Status
= ObReferenceObjectByHandle(SectionHandle
,
4257 MmSectionObjectType
,
4259 (PVOID
*)(PVOID
)&Section
,
4261 if (NT_SUCCESS(Status
))
4263 switch (SectionInformationClass
)
4265 case SectionBasicInformation
:
4267 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4271 Sbi
->Attributes
= Section
->AllocationAttributes
;
4272 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4274 Sbi
->BaseAddress
= 0;
4275 Sbi
->Size
.QuadPart
= 0;
4279 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4280 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4283 if (ResultLength
!= NULL
)
4285 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4287 Status
= STATUS_SUCCESS
;
4289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4291 Status
= _SEH2_GetExceptionCode();
4298 case SectionImageInformation
:
4300 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4304 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4305 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4307 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4308 ImageSectionObject
= Section
->ImageSection
;
4310 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4311 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4312 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4313 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4314 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4315 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4316 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4317 Sii
->Machine
= ImageSectionObject
->Machine
;
4318 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4321 if (ResultLength
!= NULL
)
4323 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4325 Status
= STATUS_SUCCESS
;
4327 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4329 Status
= _SEH2_GetExceptionCode();
4337 ObDereferenceObject(Section
);
4345 * Extends size of file backed section.
4347 * @param SectionHandle
4348 * Handle to the section object. It must be opened with
4349 * SECTION_EXTEND_SIZE access.
4350 * @param NewMaximumSize
4351 * New maximum size of the section in bytes.
4355 * @todo Move the actual code to internal function MmExtendSection.
4359 NtExtendSection(IN HANDLE SectionHandle
,
4360 IN PLARGE_INTEGER NewMaximumSize
)
4362 LARGE_INTEGER SafeNewMaximumSize
;
4363 PROS_SECTION_OBJECT Section
;
4364 KPROCESSOR_MODE PreviousMode
;
4365 NTSTATUS Status
= STATUS_SUCCESS
;
4367 PreviousMode
= ExGetPreviousMode();
4369 if(PreviousMode
!= KernelMode
)
4373 /* make a copy on the stack */
4374 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4375 NewMaximumSize
= &SafeNewMaximumSize
;
4377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4379 Status
= _SEH2_GetExceptionCode();
4383 if(!NT_SUCCESS(Status
))
4389 Status
= ObReferenceObjectByHandle(SectionHandle
,
4390 SECTION_EXTEND_SIZE
,
4391 MmSectionObjectType
,
4395 if (!NT_SUCCESS(Status
))
4400 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4402 ObfDereferenceObject(Section
);
4403 return STATUS_INVALID_PARAMETER
;
4407 * - Acquire file extneding resource.
4408 * - Check if we're not resizing the section below it's actual size!
4409 * - Extend segments if needed.
4410 * - Set file information (FileAllocationInformation) to the new size.
4411 * - Release file extending resource.
4414 ObDereferenceObject(Section
);
4416 return STATUS_NOT_IMPLEMENTED
;
4420 /**********************************************************************
4422 * MmAllocateSection@4
4432 * Code taken from ntoskrnl/mm/special.c.
4437 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4442 PMM_AVL_TABLE AddressSpace
;
4443 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4445 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4447 BoundaryAddressMultiple
.QuadPart
= 0;
4449 AddressSpace
= MmGetKernelAddressSpace();
4450 Result
= BaseAddress
;
4451 MmLockAddressSpace(AddressSpace
);
4452 Status
= MmCreateMemoryArea (AddressSpace
,
4460 BoundaryAddressMultiple
);
4461 MmUnlockAddressSpace(AddressSpace
);
4463 if (!NT_SUCCESS(Status
))
4467 DPRINT("Result %p\n",Result
);
4469 /* Create a virtual mapping for this memory area */
4470 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4472 return ((PVOID
)Result
);
4476 /**********************************************************************
4478 * MmMapViewOfSection
4481 * Maps a view of a section into the virtual address space of a
4486 * Pointer to the section object.
4489 * Pointer to the process.
4492 * Desired base address (or NULL) on entry;
4493 * Actual base address of the view on exit.
4496 * Number of high order address bits that must be zero.
4499 * Size in bytes of the initially committed section of
4503 * Offset in bytes from the beginning of the section
4504 * to the beginning of the view.
4507 * Desired length of map (or zero to map all) on entry
4508 * Actual length mapped on exit.
4510 * InheritDisposition
4511 * Specified how the view is to be shared with
4515 * Type of allocation for the pages.
4518 * Protection for the committed region of the view.
4526 MmMapViewOfSection(IN PVOID SectionObject
,
4527 IN PEPROCESS Process
,
4528 IN OUT PVOID
*BaseAddress
,
4529 IN ULONG_PTR ZeroBits
,
4530 IN SIZE_T CommitSize
,
4531 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4532 IN OUT PSIZE_T ViewSize
,
4533 IN SECTION_INHERIT InheritDisposition
,
4534 IN ULONG AllocationType
,
4537 PROS_SECTION_OBJECT Section
;
4538 PMM_AVL_TABLE AddressSpace
;
4540 NTSTATUS Status
= STATUS_SUCCESS
;
4544 if (Protect
!= PAGE_READONLY
&&
4545 Protect
!= PAGE_READWRITE
&&
4546 Protect
!= PAGE_WRITECOPY
&&
4547 Protect
!= PAGE_EXECUTE
&&
4548 Protect
!= PAGE_EXECUTE_READ
&&
4549 Protect
!= PAGE_EXECUTE_READWRITE
&&
4550 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4552 return STATUS_INVALID_PAGE_PROTECTION
;
4556 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4557 AddressSpace
= &Process
->VadRoot
;
4559 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4561 MmLockAddressSpace(AddressSpace
);
4563 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4567 ULONG_PTR ImageBase
;
4569 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4570 PMM_SECTION_SEGMENT SectionSegments
;
4572 ImageSectionObject
= Section
->ImageSection
;
4573 SectionSegments
= ImageSectionObject
->Segments
;
4574 NrSegments
= ImageSectionObject
->NrSegments
;
4577 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4580 ImageBase
= ImageSectionObject
->ImageBase
;
4584 for (i
= 0; i
< NrSegments
; i
++)
4586 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4588 ULONG_PTR MaxExtent
;
4589 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4590 SectionSegments
[i
].Length
;
4591 ImageSize
= max(ImageSize
, MaxExtent
);
4595 ImageSectionObject
->ImageSize
= ImageSize
;
4597 /* Check there is enough space to map the section at that point. */
4598 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4599 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4601 /* Fail if the user requested a fixed base address. */
4602 if ((*BaseAddress
) != NULL
)
4604 MmUnlockAddressSpace(AddressSpace
);
4605 return(STATUS_UNSUCCESSFUL
);
4607 /* Otherwise find a gap to map the image. */
4608 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4611 MmUnlockAddressSpace(AddressSpace
);
4612 return(STATUS_UNSUCCESSFUL
);
4616 for (i
= 0; i
< NrSegments
; i
++)
4618 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4620 PVOID SBaseAddress
= (PVOID
)
4621 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4622 MmLockSectionSegment(&SectionSegments
[i
]);
4623 Status
= MmMapViewOfSegment(AddressSpace
,
4625 &SectionSegments
[i
],
4627 SectionSegments
[i
].Length
,
4628 SectionSegments
[i
].Protection
,
4631 MmUnlockSectionSegment(&SectionSegments
[i
]);
4632 if (!NT_SUCCESS(Status
))
4634 MmUnlockAddressSpace(AddressSpace
);
4640 *BaseAddress
= (PVOID
)ImageBase
;
4644 /* check for write access */
4645 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4646 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4648 MmUnlockAddressSpace(AddressSpace
);
4649 return STATUS_SECTION_PROTECTION
;
4651 /* check for read access */
4652 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4653 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4655 MmUnlockAddressSpace(AddressSpace
);
4656 return STATUS_SECTION_PROTECTION
;
4658 /* check for execute access */
4659 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4660 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4662 MmUnlockAddressSpace(AddressSpace
);
4663 return STATUS_SECTION_PROTECTION
;
4666 if (ViewSize
== NULL
)
4668 /* Following this pointer would lead to us to the dark side */
4669 /* What to do? Bugcheck? Return status? Do the mambo? */
4670 KeBugCheck(MEMORY_MANAGEMENT
);
4673 if (SectionOffset
== NULL
)
4679 ViewOffset
= SectionOffset
->u
.LowPart
;
4682 if ((ViewOffset
% PAGE_SIZE
) != 0)
4684 MmUnlockAddressSpace(AddressSpace
);
4685 return(STATUS_MAPPED_ALIGNMENT
);
4688 if ((*ViewSize
) == 0)
4690 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4692 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4694 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4697 MmLockSectionSegment(Section
->Segment
);
4698 Status
= MmMapViewOfSegment(AddressSpace
,
4705 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4706 MmUnlockSectionSegment(Section
->Segment
);
4707 if (!NT_SUCCESS(Status
))
4709 MmUnlockAddressSpace(AddressSpace
);
4714 MmUnlockAddressSpace(AddressSpace
);
4716 return(STATUS_SUCCESS
);
4723 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4724 IN PLARGE_INTEGER NewFileSize
)
4735 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4745 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4746 IN MMFLUSH_TYPE FlushType
)
4750 case MmFlushForDelete
:
4751 if (SectionObjectPointer
->ImageSectionObject
||
4752 SectionObjectPointer
->DataSectionObject
)
4756 CcRosSetRemoveOnClose(SectionObjectPointer
);
4758 case MmFlushForWrite
:
4768 MmForceSectionClosed (
4769 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4770 IN BOOLEAN DelayClose
)
4781 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4782 OUT PVOID
* MappedBase
,
4783 IN OUT PSIZE_T ViewSize
)
4785 PROS_SECTION_OBJECT Section
;
4786 PMM_AVL_TABLE AddressSpace
;
4789 DPRINT("MmMapViewInSystemSpace() called\n");
4791 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4792 AddressSpace
= MmGetKernelAddressSpace();
4794 MmLockAddressSpace(AddressSpace
);
4797 if ((*ViewSize
) == 0)
4799 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4801 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4803 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4806 MmLockSectionSegment(Section
->Segment
);
4809 Status
= MmMapViewOfSegment(AddressSpace
,
4818 MmUnlockSectionSegment(Section
->Segment
);
4819 MmUnlockAddressSpace(AddressSpace
);
4829 MmMapViewInSessionSpace (
4831 OUT PVOID
*MappedBase
,
4832 IN OUT PSIZE_T ViewSize
4836 return STATUS_NOT_IMPLEMENTED
;
4844 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4846 PMM_AVL_TABLE AddressSpace
;
4849 DPRINT("MmUnmapViewInSystemSpace() called\n");
4851 AddressSpace
= MmGetKernelAddressSpace();
4853 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4863 MmUnmapViewInSessionSpace (
4868 return STATUS_NOT_IMPLEMENTED
;
4875 MmSetBankedSection (ULONG Unknown0
,
4883 return (STATUS_NOT_IMPLEMENTED
);
4887 /**********************************************************************
4892 * Creates a section object.
4895 * SectionObject (OUT)
4896 * Caller supplied storage for the resulting pointer
4897 * to a SECTION_OBJECT instance;
4900 * Specifies the desired access to the section can be a
4902 * STANDARD_RIGHTS_REQUIRED |
4904 * SECTION_MAP_WRITE |
4905 * SECTION_MAP_READ |
4906 * SECTION_MAP_EXECUTE
4908 * ObjectAttributes [OPTIONAL]
4909 * Initialized attributes for the object can be used
4910 * to create a named section;
4913 * Maximizes the size of the memory section. Must be
4914 * non-NULL for a page-file backed section.
4915 * If value specified for a mapped file and the file is
4916 * not large enough, file will be extended.
4918 * SectionPageProtection
4919 * Can be a combination of:
4925 * AllocationAttributes
4926 * Can be a combination of:
4931 * Handle to a file to create a section mapped to a file
4932 * instead of a memory backed section;
4943 MmCreateSection (OUT PVOID
* Section
,
4944 IN ACCESS_MASK DesiredAccess
,
4945 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4946 IN PLARGE_INTEGER MaximumSize
,
4947 IN ULONG SectionPageProtection
,
4948 IN ULONG AllocationAttributes
,
4949 IN HANDLE FileHandle OPTIONAL
,
4950 IN PFILE_OBJECT File OPTIONAL
)
4953 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4956 * Check the protection
4958 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4959 if (Protection
!= PAGE_NOACCESS
&&
4960 Protection
!= PAGE_READONLY
&&
4961 Protection
!= PAGE_READWRITE
&&
4962 Protection
!= PAGE_WRITECOPY
&&
4963 Protection
!= PAGE_EXECUTE
&&
4964 Protection
!= PAGE_EXECUTE_READ
&&
4965 Protection
!= PAGE_EXECUTE_READWRITE
&&
4966 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4968 return STATUS_INVALID_PAGE_PROTECTION
;
4971 if (AllocationAttributes
& SEC_IMAGE
)
4973 return(MmCreateImageSection(SectionObject
,
4977 SectionPageProtection
,
4978 AllocationAttributes
,
4982 if (FileHandle
!= NULL
)
4984 return(MmCreateDataFileSection(SectionObject
,
4988 SectionPageProtection
,
4989 AllocationAttributes
,
4993 return(MmCreatePageFileSection(SectionObject
,
4997 SectionPageProtection
,
4998 AllocationAttributes
));
5003 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5004 IN OUT PULONG_PTR NumberOfPages
,
5005 IN OUT PULONG_PTR UserPfnArray
)
5008 return STATUS_NOT_IMPLEMENTED
;
5013 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5014 IN ULONG_PTR NumberOfPages
,
5015 IN OUT PULONG_PTR UserPfnArray
)
5018 return STATUS_NOT_IMPLEMENTED
;
5023 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5024 IN ULONG_PTR NumberOfPages
,
5025 IN OUT PULONG_PTR UserPfnArray
)
5028 return STATUS_NOT_IMPLEMENTED
;
5033 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5034 IN OUT PULONG_PTR NumberOfPages
,
5035 IN OUT PULONG_PTR UserPfnArray
)
5038 return STATUS_NOT_IMPLEMENTED
;
5043 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5044 IN PVOID File2MappedAsFile
)
5047 return STATUS_NOT_IMPLEMENTED
;