2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, TAG('M', 'm', ' ', ' '));
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
153 PROS_SECTION_OBJECT Section
;
154 PMEMORY_AREA MemoryArea
;
155 PMMSUPPORT AddressSpace
;
156 POBJECT_NAME_INFORMATION ModuleNameInformation
;
157 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
159 /* Get the MM_AVL_TABLE from EPROCESS */
160 if (Address
>= MmSystemRangeStart
)
162 AddressSpace
= MmGetKernelAddressSpace();
166 AddressSpace
= &PsGetCurrentProcess()->Vm
;
169 /* Lock address space */
170 MmLockAddressSpace(AddressSpace
);
172 /* Locate the memory area for the process by address */
173 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
175 /* Make sure it's a section view type */
176 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
178 /* Get the section pointer to the SECTION_OBJECT */
179 Section
= MemoryArea
->Data
.SectionData
.Section
;
181 /* Unlock address space */
182 MmUnlockAddressSpace(AddressSpace
);
184 /* Get the filename of the section */
185 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
187 if (NT_SUCCESS(Status
))
189 /* Init modulename */
190 RtlCreateUnicodeString(ModuleName
,
191 ModuleNameInformation
->Name
.Buffer
);
193 /* Free temp taged buffer from MmGetFileNameForSection() */
194 ExFreePoolWithTag(ModuleNameInformation
, TAG('M', 'm', ' ', ' '));
195 DPRINT("Found ModuleName %S by address %p\n",
196 ModuleName
->Buffer
,Address
);
201 /* Unlock address space */
202 MmUnlockAddressSpace(AddressSpace
);
208 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
211 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
212 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
213 * RETURNS: Status of the wait.
216 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
218 LARGE_INTEGER Timeout
;
219 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
221 Timeout
.QuadPart
= -100000000LL; // 10 sec
224 Timeout
.QuadPart
= -100000000; // 10 sec
227 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
232 * FUNCTION: Sets the page op completion event and releases the page op.
233 * ARGUMENTS: PMM_PAGEOP.
234 * RETURNS: In shorter time than it takes you to even read this
235 * description, so don't even think about geting a mug of coffee.
238 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
240 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
241 MmReleasePageOp(PageOp
);
246 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
247 * ARGUMENTS: PFILE_OBJECT to wait for.
248 * RETURNS: Status of the wait.
251 MmspWaitForFileLock(PFILE_OBJECT File
)
253 return STATUS_SUCCESS
;
254 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
259 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
262 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
264 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
266 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
268 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
276 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
278 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
280 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
281 PMM_SECTION_SEGMENT SectionSegments
;
285 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
286 NrSegments
= ImageSectionObject
->NrSegments
;
287 SectionSegments
= ImageSectionObject
->Segments
;
288 for (i
= 0; i
< NrSegments
; i
++)
290 if (SectionSegments
[i
].ReferenceCount
!= 0)
292 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
293 SectionSegments
[i
].ReferenceCount
);
294 KeBugCheck(MEMORY_MANAGEMENT
);
296 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
298 ExFreePool(ImageSectionObject
->Segments
);
299 ExFreePool(ImageSectionObject
);
300 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
302 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
304 PMM_SECTION_SEGMENT Segment
;
306 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
309 if (Segment
->ReferenceCount
!= 0)
311 DPRINT1("Data segment still referenced\n");
312 KeBugCheck(MEMORY_MANAGEMENT
);
314 MmFreePageTablesSectionSegment(Segment
);
316 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
322 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
324 ExAcquireFastMutex(&Segment
->Lock
);
329 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
331 ExReleaseFastMutex(&Segment
->Lock
);
336 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
340 PSECTION_PAGE_TABLE Table
;
341 ULONG DirectoryOffset
;
344 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
346 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
350 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
351 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
355 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
356 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
357 TAG_SECTION_PAGE_TABLE
);
360 KeBugCheck(MEMORY_MANAGEMENT
);
362 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
363 DPRINT("Table %x\n", Table
);
366 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
367 Table
->Entry
[TableOffset
] = Entry
;
373 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
376 PSECTION_PAGE_TABLE Table
;
378 ULONG DirectoryOffset
;
381 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
383 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
385 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
389 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
390 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
391 DPRINT("Table %x\n", Table
);
397 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
398 Entry
= Table
->Entry
[TableOffset
];
404 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
409 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
412 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
413 KeBugCheck(MEMORY_MANAGEMENT
);
415 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
417 DPRINT1("Maximum share count reached\n");
418 KeBugCheck(MEMORY_MANAGEMENT
);
420 if (IS_SWAP_FROM_SSE(Entry
))
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
430 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
431 PMM_SECTION_SEGMENT Segment
,
437 BOOLEAN IsDirectMapped
= FALSE
;
439 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
442 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
447 DPRINT1("Zero share count for unshare\n");
448 KeBugCheck(MEMORY_MANAGEMENT
);
450 if (IS_SWAP_FROM_SSE(Entry
))
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
456 * If we reducing the share count of this entry to zero then set the entry
457 * to zero and tell the cache the page is no longer mapped.
459 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
461 PFILE_OBJECT FileObject
;
463 SWAPENTRY SavedSwapEntry
;
465 BOOLEAN IsImageSection
;
468 FileOffset
= Offset
+ Segment
->FileOffset
;
470 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
472 Page
= PFN_FROM_SSE(Entry
);
473 FileObject
= Section
->FileObject
;
474 if (FileObject
!= NULL
&&
475 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
478 if ((FileOffset
% PAGE_SIZE
) == 0 &&
479 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
482 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
483 IsDirectMapped
= TRUE
;
484 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
488 KeBugCheck(MEMORY_MANAGEMENT
);
493 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
494 if (SavedSwapEntry
== 0)
497 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
498 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
502 * Try to page out this page and set the swap entry
503 * within the section segment. There exist no rmap entry
504 * for this page. The pager thread can't page out a
505 * page without a rmap entry.
507 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
511 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
514 MmReleasePageMemoryConsumer(MC_USER
, Page
);
520 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
521 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
529 * We hold all locks. Nobody can do something with the current
530 * process and the current segment (also not within an other process).
533 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
540 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
541 MmSetSavedSwapEntryPage(Page
, 0);
543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
547 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
548 KeBugCheck(MEMORY_MANAGEMENT
);
554 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
556 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
559 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
562 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
565 PCACHE_SEGMENT CacheSeg
;
566 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
567 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
579 MiReadPage(PMEMORY_AREA MemoryArea
,
583 * FUNCTION: Read a page for a section backed memory area.
585 * MemoryArea - Memory area to read the page for.
586 * Offset - Offset of the page to read.
587 * Page - Variable that receives a page contains the read data.
594 PCACHE_SEGMENT CacheSeg
;
595 PFILE_OBJECT FileObject
;
599 BOOLEAN IsImageSection
;
602 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
603 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
604 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
605 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
606 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
610 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
613 * If the file system is letting us go directly to the cache and the
614 * memory area was mapped at an offset in the file which is page aligned
615 * then get the related cache segment.
617 if ((FileOffset
% PAGE_SIZE
) == 0 &&
618 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
619 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
623 * Get the related cache segment; we use a lower level interface than
624 * filesystems do because it is safe for us to use an offset with a
625 * alignment less than the file system block size.
627 Status
= CcRosGetCacheSegment(Bcb
,
633 if (!NT_SUCCESS(Status
))
640 * If the cache segment isn't up to date then call the file
641 * system to read in the data.
643 Status
= ReadCacheSegment(CacheSeg
);
644 if (!NT_SUCCESS(Status
))
646 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
651 * Retrieve the page from the cache segment that we actually want.
653 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
654 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
656 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
663 ULONG CacheSegOffset
;
666 * Allocate a page, this is rather complicated by the possibility
667 * we might have to move other things out of memory
669 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
670 if (!NT_SUCCESS(Status
))
674 Status
= CcRosGetCacheSegment(Bcb
,
680 if (!NT_SUCCESS(Status
))
687 * If the cache segment isn't up to date then call the file
688 * system to read in the data.
690 Status
= ReadCacheSegment(CacheSeg
);
691 if (!NT_SUCCESS(Status
))
693 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
698 Process
= PsGetCurrentProcess();
699 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
700 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
701 Length
= RawLength
- SegOffset
;
702 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
704 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
706 else if (CacheSegOffset
>= PAGE_SIZE
)
708 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
712 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
713 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
714 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
715 Status
= CcRosGetCacheSegment(Bcb
,
716 FileOffset
+ CacheSegOffset
,
721 if (!NT_SUCCESS(Status
))
728 * If the cache segment isn't up to date then call the file
729 * system to read in the data.
731 Status
= ReadCacheSegment(CacheSeg
);
732 if (!NT_SUCCESS(Status
))
734 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
738 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
739 if (Length
< PAGE_SIZE
)
741 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
745 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
748 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
749 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
751 return(STATUS_SUCCESS
);
756 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
757 MEMORY_AREA
* MemoryArea
,
765 PROS_SECTION_OBJECT Section
;
766 PMM_SECTION_SEGMENT Segment
;
772 BOOLEAN HasSwapEntry
;
773 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
776 * There is a window between taking the page fault and locking the
777 * address space when another thread could load the page so we check
780 if (MmIsPagePresent(Process
, Address
))
784 MmLockPage(MmGetPfnForProcess(Process
, Address
));
786 return(STATUS_SUCCESS
);
789 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
790 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
791 + MemoryArea
->Data
.SectionData
.ViewOffset
;
793 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
794 Section
= MemoryArea
->Data
.SectionData
.Section
;
795 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
796 &MemoryArea
->Data
.SectionData
.RegionListHead
,
801 MmLockSectionSegment(Segment
);
804 * Check if this page needs to be mapped COW
806 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
807 (Region
->Protect
== PAGE_READWRITE
||
808 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
810 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
814 Attributes
= Region
->Protect
;
818 * Get or create a page operation descriptor
820 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
823 DPRINT1("MmGetPageOp failed\n");
824 KeBugCheck(MEMORY_MANAGEMENT
);
828 * Check if someone else is already handling this fault, if so wait
831 if (PageOp
->Thread
!= PsGetCurrentThread())
833 MmUnlockSectionSegment(Segment
);
834 MmUnlockAddressSpace(AddressSpace
);
835 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
837 * Check for various strange conditions
839 if (Status
!= STATUS_SUCCESS
)
841 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
842 KeBugCheck(MEMORY_MANAGEMENT
);
844 if (PageOp
->Status
== STATUS_PENDING
)
846 DPRINT1("Woke for page op before completion\n");
847 KeBugCheck(MEMORY_MANAGEMENT
);
849 MmLockAddressSpace(AddressSpace
);
851 * If this wasn't a pagein then restart the operation
853 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
855 MmspCompleteAndReleasePageOp(PageOp
);
856 DPRINT("Address 0x%.8X\n", Address
);
857 return(STATUS_MM_RESTART_OPERATION
);
861 * If the thread handling this fault has failed then we don't retry
863 if (!NT_SUCCESS(PageOp
->Status
))
865 Status
= PageOp
->Status
;
866 MmspCompleteAndReleasePageOp(PageOp
);
867 DPRINT("Address 0x%.8X\n", Address
);
870 MmLockSectionSegment(Segment
);
872 * If the completed fault was for another address space then set the
875 if (!MmIsPagePresent(Process
, Address
))
877 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
878 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
880 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
883 * The page was a private page in another or in our address space
885 MmUnlockSectionSegment(Segment
);
886 MmspCompleteAndReleasePageOp(PageOp
);
887 return(STATUS_MM_RESTART_OPERATION
);
890 Page
= PFN_FROM_SSE(Entry
);
892 MmSharePageEntrySectionSegment(Segment
, Offset
);
894 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
895 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
897 Status
= MmCreateVirtualMapping(Process
,
902 if (!NT_SUCCESS(Status
))
904 DPRINT1("Unable to create virtual mapping\n");
905 KeBugCheck(MEMORY_MANAGEMENT
);
907 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
913 MmUnlockSectionSegment(Segment
);
914 PageOp
->Status
= STATUS_SUCCESS
;
915 MmspCompleteAndReleasePageOp(PageOp
);
916 DPRINT("Address 0x%.8X\n", Address
);
917 return(STATUS_SUCCESS
);
920 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
924 * Must be private page we have swapped out.
931 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
933 DPRINT1("Found a swaped out private page in a pagefile section.\n");
934 KeBugCheck(MEMORY_MANAGEMENT
);
937 MmUnlockSectionSegment(Segment
);
938 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
940 MmUnlockAddressSpace(AddressSpace
);
941 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
942 if (!NT_SUCCESS(Status
))
944 KeBugCheck(MEMORY_MANAGEMENT
);
947 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
951 KeBugCheck(MEMORY_MANAGEMENT
);
953 MmLockAddressSpace(AddressSpace
);
954 Status
= MmCreateVirtualMapping(Process
,
959 if (!NT_SUCCESS(Status
))
961 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
962 KeBugCheck(MEMORY_MANAGEMENT
);
967 * Store the swap entry for later use.
969 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
972 * Add the page to the process's working set
974 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
977 * Finish the operation
983 PageOp
->Status
= STATUS_SUCCESS
;
984 MmspCompleteAndReleasePageOp(PageOp
);
985 DPRINT("Address 0x%.8X\n", Address
);
986 return(STATUS_SUCCESS
);
990 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
992 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
994 MmUnlockSectionSegment(Segment
);
996 * Just map the desired physical page
998 Page
= Offset
>> PAGE_SHIFT
;
999 Status
= MmCreateVirtualMappingUnsafe(Process
,
1004 if (!NT_SUCCESS(Status
))
1006 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1011 * Don't add an rmap entry since the page mapped could be for
1016 MmLockPageUnsafe(Page
);
1020 * Cleanup and release locks
1022 PageOp
->Status
= STATUS_SUCCESS
;
1023 MmspCompleteAndReleasePageOp(PageOp
);
1024 DPRINT("Address 0x%.8X\n", Address
);
1025 return(STATUS_SUCCESS
);
1029 * Map anonymous memory for BSS sections
1031 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1033 MmUnlockSectionSegment(Segment
);
1034 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1035 if (!NT_SUCCESS(Status
))
1037 MmUnlockAddressSpace(AddressSpace
);
1038 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1039 MmLockAddressSpace(AddressSpace
);
1041 if (!NT_SUCCESS(Status
))
1043 KeBugCheck(MEMORY_MANAGEMENT
);
1045 Status
= MmCreateVirtualMapping(Process
,
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1053 KeBugCheck(MEMORY_MANAGEMENT
);
1056 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1063 * Cleanup and release locks
1065 PageOp
->Status
= STATUS_SUCCESS
;
1066 MmspCompleteAndReleasePageOp(PageOp
);
1067 DPRINT("Address 0x%.8X\n", Address
);
1068 return(STATUS_SUCCESS
);
1072 * Get the entry corresponding to the offset within the section
1074 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1079 * If the entry is zero (and it can't change because we have
1080 * locked the segment) then we need to load the page.
1084 * Release all our locks and read in the page from disk
1086 MmUnlockSectionSegment(Segment
);
1087 MmUnlockAddressSpace(AddressSpace
);
1089 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1090 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1092 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1093 if (!NT_SUCCESS(Status
))
1095 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1100 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1101 if (!NT_SUCCESS(Status
))
1103 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1106 if (!NT_SUCCESS(Status
))
1109 * FIXME: What do we know in this case?
1112 * Cleanup and release locks
1114 MmLockAddressSpace(AddressSpace
);
1115 PageOp
->Status
= Status
;
1116 MmspCompleteAndReleasePageOp(PageOp
);
1117 DPRINT("Address 0x%.8X\n", Address
);
1121 * Relock the address space and segment
1123 MmLockAddressSpace(AddressSpace
);
1124 MmLockSectionSegment(Segment
);
1127 * Check the entry. No one should change the status of a page
1128 * that has a pending page-in.
1130 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1131 if (Entry
!= Entry1
)
1133 DPRINT1("Someone changed ppte entry while we slept\n");
1134 KeBugCheck(MEMORY_MANAGEMENT
);
1138 * Mark the offset within the section as having valid, in-memory
1141 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1142 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1143 MmUnlockSectionSegment(Segment
);
1145 Status
= MmCreateVirtualMapping(Process
,
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT1("Unable to create virtual mapping\n");
1153 KeBugCheck(MEMORY_MANAGEMENT
);
1155 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1161 PageOp
->Status
= STATUS_SUCCESS
;
1162 MmspCompleteAndReleasePageOp(PageOp
);
1163 DPRINT("Address 0x%.8X\n", Address
);
1164 return(STATUS_SUCCESS
);
1166 else if (IS_SWAP_FROM_SSE(Entry
))
1168 SWAPENTRY SwapEntry
;
1170 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1173 * Release all our locks and read in the page from disk
1175 MmUnlockSectionSegment(Segment
);
1177 MmUnlockAddressSpace(AddressSpace
);
1179 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1180 if (!NT_SUCCESS(Status
))
1182 KeBugCheck(MEMORY_MANAGEMENT
);
1185 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1186 if (!NT_SUCCESS(Status
))
1188 KeBugCheck(MEMORY_MANAGEMENT
);
1192 * Relock the address space and segment
1194 MmLockAddressSpace(AddressSpace
);
1195 MmLockSectionSegment(Segment
);
1198 * Check the entry. No one should change the status of a page
1199 * that has a pending page-in.
1201 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1202 if (Entry
!= Entry1
)
1204 DPRINT1("Someone changed ppte entry while we slept\n");
1205 KeBugCheck(MEMORY_MANAGEMENT
);
1209 * Mark the offset within the section as having valid, in-memory
1212 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1213 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1214 MmUnlockSectionSegment(Segment
);
1217 * Save the swap entry.
1219 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1220 Status
= MmCreateVirtualMapping(Process
,
1225 if (!NT_SUCCESS(Status
))
1227 DPRINT1("Unable to create virtual mapping\n");
1228 KeBugCheck(MEMORY_MANAGEMENT
);
1230 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1235 PageOp
->Status
= STATUS_SUCCESS
;
1236 MmspCompleteAndReleasePageOp(PageOp
);
1237 DPRINT("Address 0x%.8X\n", Address
);
1238 return(STATUS_SUCCESS
);
1243 * If the section offset is already in-memory and valid then just
1244 * take another reference to the page
1247 Page
= PFN_FROM_SSE(Entry
);
1249 MmSharePageEntrySectionSegment(Segment
, Offset
);
1250 MmUnlockSectionSegment(Segment
);
1252 Status
= MmCreateVirtualMapping(Process
,
1257 if (!NT_SUCCESS(Status
))
1259 DPRINT1("Unable to create virtual mapping\n");
1260 KeBugCheck(MEMORY_MANAGEMENT
);
1262 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1267 PageOp
->Status
= STATUS_SUCCESS
;
1268 MmspCompleteAndReleasePageOp(PageOp
);
1269 DPRINT("Address 0x%.8X\n", Address
);
1270 return(STATUS_SUCCESS
);
1276 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1277 MEMORY_AREA
* MemoryArea
,
1281 PMM_SECTION_SEGMENT Segment
;
1282 PROS_SECTION_OBJECT Section
;
1291 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1293 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1296 * Check if the page has been paged out or has already been set readwrite
1298 if (!MmIsPagePresent(Process
, Address
) ||
1299 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1301 DPRINT("Address 0x%.8X\n", Address
);
1302 return(STATUS_SUCCESS
);
1306 * Find the offset of the page
1308 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1309 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1310 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1312 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1313 Section
= MemoryArea
->Data
.SectionData
.Section
;
1314 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1315 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1320 MmLockSectionSegment(Segment
);
1322 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1323 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1325 MmUnlockSectionSegment(Segment
);
1328 * Check if we are doing COW
1330 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1331 (Region
->Protect
== PAGE_READWRITE
||
1332 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1334 DPRINT("Address 0x%.8X\n", Address
);
1335 return(STATUS_ACCESS_VIOLATION
);
1338 if (IS_SWAP_FROM_SSE(Entry
) ||
1339 PFN_FROM_SSE(Entry
) != OldPage
)
1341 /* This is a private page. We must only change the page protection. */
1342 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1343 return(STATUS_SUCCESS
);
1347 * Get or create a pageop
1349 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1350 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1353 DPRINT1("MmGetPageOp failed\n");
1354 KeBugCheck(MEMORY_MANAGEMENT
);
1358 * Wait for any other operations to complete
1360 if (PageOp
->Thread
!= PsGetCurrentThread())
1362 MmUnlockAddressSpace(AddressSpace
);
1363 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1365 * Check for various strange conditions
1367 if (Status
== STATUS_TIMEOUT
)
1369 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1370 KeBugCheck(MEMORY_MANAGEMENT
);
1372 if (PageOp
->Status
== STATUS_PENDING
)
1374 DPRINT1("Woke for page op before completion\n");
1375 KeBugCheck(MEMORY_MANAGEMENT
);
1378 * Restart the operation
1380 MmLockAddressSpace(AddressSpace
);
1381 MmspCompleteAndReleasePageOp(PageOp
);
1382 DPRINT("Address 0x%.8X\n", Address
);
1383 return(STATUS_MM_RESTART_OPERATION
);
1387 * Release locks now we have the pageop
1389 MmUnlockAddressSpace(AddressSpace
);
1394 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1395 if (!NT_SUCCESS(Status
))
1397 KeBugCheck(MEMORY_MANAGEMENT
);
1403 MiCopyFromUserPage(NewPage
, PAddress
);
1405 MmLockAddressSpace(AddressSpace
);
1407 * Delete the old entry.
1409 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1412 * Set the PTE to point to the new page
1414 Status
= MmCreateVirtualMapping(Process
,
1419 if (!NT_SUCCESS(Status
))
1421 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1422 KeBugCheck(MEMORY_MANAGEMENT
);
1425 if (!NT_SUCCESS(Status
))
1427 DPRINT1("Unable to create virtual mapping\n");
1428 KeBugCheck(MEMORY_MANAGEMENT
);
1432 MmLockPage(NewPage
);
1433 MmUnlockPage(OldPage
);
1437 * Unshare the old page.
1439 MmDeleteRmap(OldPage
, Process
, PAddress
);
1440 MmInsertRmap(NewPage
, Process
, PAddress
);
1441 MmLockSectionSegment(Segment
);
1442 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1443 MmUnlockSectionSegment(Segment
);
1445 PageOp
->Status
= STATUS_SUCCESS
;
1446 MmspCompleteAndReleasePageOp(PageOp
);
1447 DPRINT("Address 0x%.8X\n", Address
);
1448 return(STATUS_SUCCESS
);
1452 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1454 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1458 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1461 MmLockAddressSpace(&Process
->Vm
);
1464 MmDeleteVirtualMapping(Process
,
1471 PageOutContext
->WasDirty
= TRUE
;
1473 if (!PageOutContext
->Private
)
1475 MmLockSectionSegment(PageOutContext
->Segment
);
1476 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1477 PageOutContext
->Segment
,
1478 PageOutContext
->Offset
,
1479 PageOutContext
->WasDirty
,
1481 MmUnlockSectionSegment(PageOutContext
->Segment
);
1485 MmUnlockAddressSpace(&Process
->Vm
);
1488 if (PageOutContext
->Private
)
1490 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1493 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1498 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1499 MEMORY_AREA
* MemoryArea
,
1504 MM_SECTION_PAGEOUT_CONTEXT Context
;
1505 SWAPENTRY SwapEntry
;
1509 PFILE_OBJECT FileObject
;
1511 BOOLEAN DirectMapped
;
1512 BOOLEAN IsImageSection
;
1513 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1515 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1518 * Get the segment and section.
1520 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1521 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1523 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1524 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1525 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1527 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1529 FileObject
= Context
.Section
->FileObject
;
1530 DirectMapped
= FALSE
;
1531 if (FileObject
!= NULL
&&
1532 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1534 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1537 * If the file system is letting us go directly to the cache and the
1538 * memory area was mapped at an offset in the file which is page aligned
1539 * then note this is a direct mapped page.
1541 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1542 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1544 DirectMapped
= TRUE
;
1550 * This should never happen since mappings of physical memory are never
1551 * placed in the rmap lists.
1553 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1555 DPRINT1("Trying to page out from physical memory section address 0x%X "
1556 "process %d\n", Address
,
1557 Process
? Process
->UniqueProcessId
: 0);
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1562 * Get the section segment entry and the physical address.
1564 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1565 if (!MmIsPagePresent(Process
, Address
))
1567 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1568 Process
? Process
->UniqueProcessId
: 0, Address
);
1569 KeBugCheck(MEMORY_MANAGEMENT
);
1571 Page
= MmGetPfnForProcess(Process
, Address
);
1572 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1575 * Prepare the context structure for the rmap delete call.
1577 Context
.WasDirty
= FALSE
;
1578 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1579 IS_SWAP_FROM_SSE(Entry
) ||
1580 PFN_FROM_SSE(Entry
) != Page
)
1582 Context
.Private
= TRUE
;
1586 Context
.Private
= FALSE
;
1590 * Take an additional reference to the page or the cache segment.
1592 if (DirectMapped
&& !Context
.Private
)
1594 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1596 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1597 KeBugCheck(MEMORY_MANAGEMENT
);
1602 MmReferencePage(Page
);
1605 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1608 * If this wasn't a private page then we should have reduced the entry to
1609 * zero by deleting all the rmaps.
1611 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1613 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1614 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1616 KeBugCheck(MEMORY_MANAGEMENT
);
1621 * If the page wasn't dirty then we can just free it as for a readonly page.
1622 * Since we unmapped all the mappings above we know it will not suddenly
1624 * If the page is from a pagefile section and has no swap entry,
1625 * we can't free the page at this point.
1627 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1628 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1630 if (Context
.Private
)
1632 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1633 Context
.WasDirty
? "dirty" : "clean", Address
);
1634 KeBugCheck(MEMORY_MANAGEMENT
);
1636 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1638 MmSetSavedSwapEntryPage(Page
, 0);
1639 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1640 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1641 PageOp
->Status
= STATUS_SUCCESS
;
1642 MmspCompleteAndReleasePageOp(PageOp
);
1643 return(STATUS_SUCCESS
);
1646 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1648 if (Context
.Private
)
1650 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1651 Context
.WasDirty
? "dirty" : "clean", Address
);
1652 KeBugCheck(MEMORY_MANAGEMENT
);
1654 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1656 MmSetSavedSwapEntryPage(Page
, 0);
1659 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1661 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1662 PageOp
->Status
= STATUS_SUCCESS
;
1663 MmspCompleteAndReleasePageOp(PageOp
);
1664 return(STATUS_SUCCESS
);
1667 else if (!Context
.Private
&& DirectMapped
)
1671 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1673 KeBugCheck(MEMORY_MANAGEMENT
);
1675 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1676 if (!NT_SUCCESS(Status
))
1678 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1681 PageOp
->Status
= STATUS_SUCCESS
;
1682 MmspCompleteAndReleasePageOp(PageOp
);
1683 return(STATUS_SUCCESS
);
1685 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1689 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1691 KeBugCheck(MEMORY_MANAGEMENT
);
1693 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1694 PageOp
->Status
= STATUS_SUCCESS
;
1695 MmspCompleteAndReleasePageOp(PageOp
);
1696 return(STATUS_SUCCESS
);
1698 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1700 MmSetSavedSwapEntryPage(Page
, 0);
1701 MmLockAddressSpace(AddressSpace
);
1702 Status
= MmCreatePageFileMapping(Process
,
1705 MmUnlockAddressSpace(AddressSpace
);
1706 if (!NT_SUCCESS(Status
))
1708 KeBugCheck(MEMORY_MANAGEMENT
);
1710 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1711 PageOp
->Status
= STATUS_SUCCESS
;
1712 MmspCompleteAndReleasePageOp(PageOp
);
1713 return(STATUS_SUCCESS
);
1717 * If necessary, allocate an entry in the paging file for this page
1721 SwapEntry
= MmAllocSwapPage();
1724 MmShowOutOfSpaceMessagePagingFile();
1725 MmLockAddressSpace(AddressSpace
);
1727 * For private pages restore the old mappings.
1729 if (Context
.Private
)
1731 Status
= MmCreateVirtualMapping(Process
,
1733 MemoryArea
->Protect
,
1736 MmSetDirtyPage(Process
, Address
);
1744 * For non-private pages if the page wasn't direct mapped then
1745 * set it back into the section segment entry so we don't loose
1746 * our copy. Otherwise it will be handled by the cache manager.
1748 Status
= MmCreateVirtualMapping(Process
,
1750 MemoryArea
->Protect
,
1753 MmSetDirtyPage(Process
, Address
);
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1760 MmUnlockAddressSpace(AddressSpace
);
1761 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1762 MmspCompleteAndReleasePageOp(PageOp
);
1763 return(STATUS_PAGEFILE_QUOTA
);
1768 * Write the page to the pagefile
1770 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1771 if (!NT_SUCCESS(Status
))
1773 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1776 * As above: undo our actions.
1777 * FIXME: Also free the swap page.
1779 MmLockAddressSpace(AddressSpace
);
1780 if (Context
.Private
)
1782 Status
= MmCreateVirtualMapping(Process
,
1784 MemoryArea
->Protect
,
1787 MmSetDirtyPage(Process
, Address
);
1794 Status
= MmCreateVirtualMapping(Process
,
1796 MemoryArea
->Protect
,
1799 MmSetDirtyPage(Process
, Address
);
1803 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1804 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1806 MmUnlockAddressSpace(AddressSpace
);
1807 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1808 MmspCompleteAndReleasePageOp(PageOp
);
1809 return(STATUS_UNSUCCESSFUL
);
1813 * Otherwise we have succeeded.
1815 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1816 MmSetSavedSwapEntryPage(Page
, 0);
1817 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1818 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1820 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1824 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1827 if (Context
.Private
)
1829 MmLockAddressSpace(AddressSpace
);
1830 Status
= MmCreatePageFileMapping(Process
,
1833 MmUnlockAddressSpace(AddressSpace
);
1834 if (!NT_SUCCESS(Status
))
1836 KeBugCheck(MEMORY_MANAGEMENT
);
1841 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1842 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1845 PageOp
->Status
= STATUS_SUCCESS
;
1846 MmspCompleteAndReleasePageOp(PageOp
);
1847 return(STATUS_SUCCESS
);
1852 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1853 PMEMORY_AREA MemoryArea
,
1858 PROS_SECTION_OBJECT Section
;
1859 PMM_SECTION_SEGMENT Segment
;
1861 SWAPENTRY SwapEntry
;
1865 PFILE_OBJECT FileObject
;
1867 BOOLEAN DirectMapped
;
1868 BOOLEAN IsImageSection
;
1869 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1871 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1873 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1874 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1877 * Get the segment and section.
1879 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1880 Section
= MemoryArea
->Data
.SectionData
.Section
;
1881 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1883 FileObject
= Section
->FileObject
;
1884 DirectMapped
= FALSE
;
1885 if (FileObject
!= NULL
&&
1886 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1888 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1891 * If the file system is letting us go directly to the cache and the
1892 * memory area was mapped at an offset in the file which is page aligned
1893 * then note this is a direct mapped page.
1895 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1896 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1898 DirectMapped
= TRUE
;
1903 * This should never happen since mappings of physical memory are never
1904 * placed in the rmap lists.
1906 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1908 DPRINT1("Trying to write back page from physical memory mapped at %X "
1909 "process %d\n", Address
,
1910 Process
? Process
->UniqueProcessId
: 0);
1911 KeBugCheck(MEMORY_MANAGEMENT
);
1915 * Get the section segment entry and the physical address.
1917 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1918 if (!MmIsPagePresent(Process
, Address
))
1920 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1921 Process
? Process
->UniqueProcessId
: 0, Address
);
1922 KeBugCheck(MEMORY_MANAGEMENT
);
1924 Page
= MmGetPfnForProcess(Process
, Address
);
1925 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1928 * Check for a private (COWed) page.
1930 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1931 IS_SWAP_FROM_SSE(Entry
) ||
1932 PFN_FROM_SSE(Entry
) != Page
)
1942 * Speculatively set all mappings of the page to clean.
1944 MmSetCleanAllRmaps(Page
);
1947 * If this page was direct mapped from the cache then the cache manager
1948 * will take care of writing it back to disk.
1950 if (DirectMapped
&& !Private
)
1952 ASSERT(SwapEntry
== 0);
1953 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1954 PageOp
->Status
= STATUS_SUCCESS
;
1955 MmspCompleteAndReleasePageOp(PageOp
);
1956 return(STATUS_SUCCESS
);
1960 * If necessary, allocate an entry in the paging file for this page
1964 SwapEntry
= MmAllocSwapPage();
1967 MmSetDirtyAllRmaps(Page
);
1968 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1969 MmspCompleteAndReleasePageOp(PageOp
);
1970 return(STATUS_PAGEFILE_QUOTA
);
1972 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1976 * Write the page to the pagefile
1978 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1979 if (!NT_SUCCESS(Status
))
1981 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1983 MmSetDirtyAllRmaps(Page
);
1984 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1985 MmspCompleteAndReleasePageOp(PageOp
);
1986 return(STATUS_UNSUCCESSFUL
);
1990 * Otherwise we have succeeded.
1992 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1993 PageOp
->Status
= STATUS_SUCCESS
;
1994 MmspCompleteAndReleasePageOp(PageOp
);
1995 return(STATUS_SUCCESS
);
1999 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2007 PMEMORY_AREA MemoryArea
;
2008 PMM_SECTION_SEGMENT Segment
;
2009 BOOLEAN DoCOW
= FALSE
;
2011 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2013 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2014 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2016 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2017 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2022 if (OldProtect
!= NewProtect
)
2024 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2026 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2027 ULONG Protect
= NewProtect
;
2030 * If we doing COW for this segment then check if the page is
2033 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2039 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2040 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2041 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2042 Page
= MmGetPfnForProcess(Process
, Address
);
2044 Protect
= PAGE_READONLY
;
2045 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2046 IS_SWAP_FROM_SSE(Entry
) ||
2047 PFN_FROM_SSE(Entry
) != Page
)
2049 Protect
= NewProtect
;
2053 if (MmIsPagePresent(Process
, Address
))
2055 MmSetPageProtect(Process
, Address
,
2064 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2065 PMEMORY_AREA MemoryArea
,
2073 ULONG_PTR MaxLength
;
2075 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2076 if (Length
> MaxLength
)
2079 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2080 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2082 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2083 Region
->Protect
!= Protect
)
2085 return STATUS_INVALID_PAGE_PROTECTION
;
2088 *OldProtect
= Region
->Protect
;
2089 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2090 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2091 BaseAddress
, Length
, Region
->Type
, Protect
,
2092 MmAlterViewAttributes
);
2098 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2100 PMEMORY_BASIC_INFORMATION Info
,
2101 PULONG ResultLength
)
2104 PVOID RegionBaseAddress
;
2105 PROS_SECTION_OBJECT Section
;
2106 PMM_SECTION_SEGMENT Segment
;
2108 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2109 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2110 Address
, &RegionBaseAddress
);
2113 return STATUS_UNSUCCESSFUL
;
2116 Section
= MemoryArea
->Data
.SectionData
.Section
;
2117 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2119 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2120 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2121 Info
->Type
= MEM_IMAGE
;
2125 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2126 Info
->Type
= MEM_MAPPED
;
2128 Info
->BaseAddress
= RegionBaseAddress
;
2129 Info
->AllocationProtect
= MemoryArea
->Protect
;
2130 Info
->RegionSize
= Region
->Length
;
2131 Info
->State
= MEM_COMMIT
;
2132 Info
->Protect
= Region
->Protect
;
2134 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2135 return(STATUS_SUCCESS
);
2140 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2145 ULONG SavedSwapEntry
;
2150 Length
= PAGE_ROUND_UP(Segment
->Length
);
2151 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2153 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2156 if (IS_SWAP_FROM_SSE(Entry
))
2158 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2162 Page
= PFN_FROM_SSE(Entry
);
2163 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2164 if (SavedSwapEntry
!= 0)
2166 MmSetSavedSwapEntryPage(Page
, 0);
2167 MmFreeSwapPage(SavedSwapEntry
);
2169 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2171 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2177 MmpDeleteSection(PVOID ObjectBody
)
2179 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2181 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2182 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2187 PMM_SECTION_SEGMENT SectionSegments
;
2190 * NOTE: Section->ImageSection can be NULL for short time
2191 * during the section creating. If we fail for some reason
2192 * until the image section is properly initialized we shouldn't
2193 * process further here.
2195 if (Section
->ImageSection
== NULL
)
2198 SectionSegments
= Section
->ImageSection
->Segments
;
2199 NrSegments
= Section
->ImageSection
->NrSegments
;
2201 for (i
= 0; i
< NrSegments
; i
++)
2203 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2205 MmLockSectionSegment(&SectionSegments
[i
]);
2207 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2208 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2212 MmpFreePageFileSegment(&SectionSegments
[i
]);
2214 MmUnlockSectionSegment(&SectionSegments
[i
]);
2221 * NOTE: Section->Segment can be NULL for short time
2222 * during the section creating.
2224 if (Section
->Segment
== NULL
)
2227 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2229 MmpFreePageFileSegment(Section
->Segment
);
2230 MmFreePageTablesSectionSegment(Section
->Segment
);
2231 ExFreePool(Section
->Segment
);
2232 Section
->Segment
= NULL
;
2236 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2239 if (Section
->FileObject
!= NULL
)
2241 CcRosDereferenceCache(Section
->FileObject
);
2242 ObDereferenceObject(Section
->FileObject
);
2243 Section
->FileObject
= NULL
;
2248 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2250 IN ACCESS_MASK GrantedAccess
,
2251 IN ULONG ProcessHandleCount
,
2252 IN ULONG SystemHandleCount
)
2254 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2255 Object
, ProcessHandleCount
);
2261 MmCreatePhysicalMemorySection(VOID
)
2263 PROS_SECTION_OBJECT PhysSection
;
2265 OBJECT_ATTRIBUTES Obj
;
2266 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2267 LARGE_INTEGER SectionSize
;
2271 * Create the section mapping physical memory
2273 SectionSize
.QuadPart
= 0xFFFFFFFF;
2274 InitializeObjectAttributes(&Obj
,
2279 Status
= MmCreateSection((PVOID
)&PhysSection
,
2283 PAGE_EXECUTE_READWRITE
,
2287 if (!NT_SUCCESS(Status
))
2289 DPRINT1("Failed to create PhysicalMemory section\n");
2290 KeBugCheck(MEMORY_MANAGEMENT
);
2292 Status
= ObInsertObject(PhysSection
,
2298 if (!NT_SUCCESS(Status
))
2300 ObDereferenceObject(PhysSection
);
2302 ObCloseHandle(Handle
, KernelMode
);
2303 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2304 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2306 return(STATUS_SUCCESS
);
2312 MmInitSectionImplementation(VOID
)
2314 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2315 UNICODE_STRING Name
;
2317 DPRINT("Creating Section Object Type\n");
2319 /* Initialize the Section object type */
2320 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2321 RtlInitUnicodeString(&Name
, L
"Section");
2322 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2323 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2324 ObjectTypeInitializer
.PoolType
= PagedPool
;
2325 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2326 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2327 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2328 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2329 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2330 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2332 return(STATUS_SUCCESS
);
2337 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2338 ACCESS_MASK DesiredAccess
,
2339 POBJECT_ATTRIBUTES ObjectAttributes
,
2340 PLARGE_INTEGER UMaximumSize
,
2341 ULONG SectionPageProtection
,
2342 ULONG AllocationAttributes
)
2344 * Create a section which is backed by the pagefile
2347 LARGE_INTEGER MaximumSize
;
2348 PROS_SECTION_OBJECT Section
;
2349 PMM_SECTION_SEGMENT Segment
;
2352 if (UMaximumSize
== NULL
)
2354 return(STATUS_UNSUCCESSFUL
);
2356 MaximumSize
= *UMaximumSize
;
2359 * Create the section
2361 Status
= ObCreateObject(ExGetPreviousMode(),
2362 MmSectionObjectType
,
2364 ExGetPreviousMode(),
2366 sizeof(ROS_SECTION_OBJECT
),
2369 (PVOID
*)(PVOID
)&Section
);
2370 if (!NT_SUCCESS(Status
))
2378 Section
->SectionPageProtection
= SectionPageProtection
;
2379 Section
->AllocationAttributes
= AllocationAttributes
;
2380 Section
->Segment
= NULL
;
2381 Section
->FileObject
= NULL
;
2382 Section
->MaximumSize
= MaximumSize
;
2383 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2384 TAG_MM_SECTION_SEGMENT
);
2385 if (Segment
== NULL
)
2387 ObDereferenceObject(Section
);
2388 return(STATUS_NO_MEMORY
);
2390 Section
->Segment
= Segment
;
2391 Segment
->ReferenceCount
= 1;
2392 ExInitializeFastMutex(&Segment
->Lock
);
2393 Segment
->FileOffset
= 0;
2394 Segment
->Protection
= SectionPageProtection
;
2395 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2396 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2397 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2398 Segment
->WriteCopy
= FALSE
;
2399 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2400 Segment
->VirtualAddress
= 0;
2401 Segment
->Characteristics
= 0;
2402 *SectionObject
= Section
;
2403 return(STATUS_SUCCESS
);
2409 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2410 ACCESS_MASK DesiredAccess
,
2411 POBJECT_ATTRIBUTES ObjectAttributes
,
2412 PLARGE_INTEGER UMaximumSize
,
2413 ULONG SectionPageProtection
,
2414 ULONG AllocationAttributes
,
2417 * Create a section backed by a data file
2420 PROS_SECTION_OBJECT Section
;
2422 LARGE_INTEGER MaximumSize
;
2423 PFILE_OBJECT FileObject
;
2424 PMM_SECTION_SEGMENT Segment
;
2426 IO_STATUS_BLOCK Iosb
;
2427 LARGE_INTEGER Offset
;
2429 FILE_STANDARD_INFORMATION FileInfo
;
2432 * Create the section
2434 Status
= ObCreateObject(ExGetPreviousMode(),
2435 MmSectionObjectType
,
2437 ExGetPreviousMode(),
2439 sizeof(ROS_SECTION_OBJECT
),
2442 (PVOID
*)(PVOID
)&Section
);
2443 if (!NT_SUCCESS(Status
))
2450 Section
->SectionPageProtection
= SectionPageProtection
;
2451 Section
->AllocationAttributes
= AllocationAttributes
;
2452 Section
->Segment
= NULL
;
2455 * Check file access required
2457 if (SectionPageProtection
& PAGE_READWRITE
||
2458 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2460 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2464 FileAccess
= FILE_READ_DATA
;
2468 * Reference the file handle
2470 Status
= ObReferenceObjectByHandle(FileHandle
,
2473 ExGetPreviousMode(),
2474 (PVOID
*)(PVOID
)&FileObject
,
2476 if (!NT_SUCCESS(Status
))
2478 ObDereferenceObject(Section
);
2483 * FIXME: This is propably not entirely correct. We can't look into
2484 * the standard FCB header because it might not be initialized yet
2485 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2486 * standard file information is filled on first request).
2488 Status
= IoQueryFileInformation(FileObject
,
2489 FileStandardInformation
,
2490 sizeof(FILE_STANDARD_INFORMATION
),
2493 if (!NT_SUCCESS(Status
))
2495 ObDereferenceObject(Section
);
2496 ObDereferenceObject(FileObject
);
2501 * FIXME: Revise this once a locking order for file size changes is
2504 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2506 MaximumSize
= *UMaximumSize
;
2510 MaximumSize
= FileInfo
.EndOfFile
;
2511 /* Mapping zero-sized files isn't allowed. */
2512 if (MaximumSize
.QuadPart
== 0)
2514 ObDereferenceObject(Section
);
2515 ObDereferenceObject(FileObject
);
2516 return STATUS_FILE_INVALID
;
2520 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2522 Status
= IoSetInformation(FileObject
,
2523 FileAllocationInformation
,
2524 sizeof(LARGE_INTEGER
),
2526 if (!NT_SUCCESS(Status
))
2528 ObDereferenceObject(Section
);
2529 ObDereferenceObject(FileObject
);
2530 return(STATUS_SECTION_NOT_EXTENDED
);
2534 if (FileObject
->SectionObjectPointer
== NULL
||
2535 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2538 * Read a bit so caching is initiated for the file object.
2539 * This is only needed because MiReadPage currently cannot
2540 * handle non-cached streams.
2542 Offset
.QuadPart
= 0;
2543 Status
= ZwReadFile(FileHandle
,
2552 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2554 ObDereferenceObject(Section
);
2555 ObDereferenceObject(FileObject
);
2558 if (FileObject
->SectionObjectPointer
== NULL
||
2559 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2561 /* FIXME: handle this situation */
2562 ObDereferenceObject(Section
);
2563 ObDereferenceObject(FileObject
);
2564 return STATUS_INVALID_PARAMETER
;
2571 Status
= MmspWaitForFileLock(FileObject
);
2572 if (Status
!= STATUS_SUCCESS
)
2574 ObDereferenceObject(Section
);
2575 ObDereferenceObject(FileObject
);
2580 * If this file hasn't been mapped as a data file before then allocate a
2581 * section segment to describe the data file mapping
2583 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2585 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2586 TAG_MM_SECTION_SEGMENT
);
2587 if (Segment
== NULL
)
2589 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2590 ObDereferenceObject(Section
);
2591 ObDereferenceObject(FileObject
);
2592 return(STATUS_NO_MEMORY
);
2594 Section
->Segment
= Segment
;
2595 Segment
->ReferenceCount
= 1;
2596 ExInitializeFastMutex(&Segment
->Lock
);
2598 * Set the lock before assigning the segment to the file object
2600 ExAcquireFastMutex(&Segment
->Lock
);
2601 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2603 Segment
->FileOffset
= 0;
2604 Segment
->Protection
= SectionPageProtection
;
2605 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2606 Segment
->Characteristics
= 0;
2607 Segment
->WriteCopy
= FALSE
;
2608 if (AllocationAttributes
& SEC_RESERVE
)
2610 Segment
->Length
= Segment
->RawLength
= 0;
2614 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2615 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2617 Segment
->VirtualAddress
= 0;
2618 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2623 * If the file is already mapped as a data file then we may need
2627 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2629 Section
->Segment
= Segment
;
2630 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2631 MmLockSectionSegment(Segment
);
2633 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2634 !(AllocationAttributes
& SEC_RESERVE
))
2636 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2637 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2640 MmUnlockSectionSegment(Segment
);
2641 Section
->FileObject
= FileObject
;
2642 Section
->MaximumSize
= MaximumSize
;
2643 CcRosReferenceCache(FileObject
);
2644 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2645 *SectionObject
= Section
;
2646 return(STATUS_SUCCESS
);
2650 TODO: not that great (declaring loaders statically, having to declare all of
2651 them, having to keep them extern, etc.), will fix in the future
2653 extern NTSTATUS NTAPI PeFmtCreateSection
2655 IN CONST VOID
* FileHeader
,
2656 IN SIZE_T FileHeaderSize
,
2658 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2660 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2661 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2664 extern NTSTATUS NTAPI ElfFmtCreateSection
2666 IN CONST VOID
* FileHeader
,
2667 IN SIZE_T FileHeaderSize
,
2669 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2671 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2672 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2675 /* TODO: this is a standard DDK/PSDK macro */
2676 #ifndef RTL_NUMBER_OF
2677 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2680 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2691 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2693 SIZE_T SizeOfSegments
;
2694 PMM_SECTION_SEGMENT Segments
;
2696 /* TODO: check for integer overflow */
2697 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2699 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2701 TAG_MM_SECTION_SEGMENT
);
2704 RtlZeroMemory(Segments
, SizeOfSegments
);
2712 ExeFmtpReadFile(IN PVOID File
,
2713 IN PLARGE_INTEGER Offset
,
2716 OUT PVOID
* AllocBase
,
2717 OUT PULONG ReadSize
)
2720 LARGE_INTEGER FileOffset
;
2722 ULONG OffsetAdjustment
;
2727 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2731 KeBugCheck(MEMORY_MANAGEMENT
);
2734 FileOffset
= *Offset
;
2736 /* Negative/special offset: it cannot be used in this context */
2737 if(FileOffset
.u
.HighPart
< 0)
2739 KeBugCheck(MEMORY_MANAGEMENT
);
2742 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2743 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2744 FileOffset
.u
.LowPart
= AdjustOffset
;
2746 BufferSize
= Length
+ OffsetAdjustment
;
2747 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2750 * It's ok to use paged pool, because this is a temporary buffer only used in
2751 * the loading of executables. The assumption is that MmCreateSection is
2752 * always called at low IRQLs and that these buffers don't survive a brief
2753 * initialization phase
2755 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2757 TAG('M', 'm', 'X', 'r'));
2762 Status
= MmspPageRead(File
,
2769 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2770 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2771 * to initialize internal state is even worse. Our cache manager is in need of
2775 IO_STATUS_BLOCK Iosb
;
2777 Status
= ZwReadFile(File
,
2787 if(NT_SUCCESS(Status
))
2789 UsedSize
= Iosb
.Information
;
2794 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2796 Status
= STATUS_IN_PAGE_ERROR
;
2797 ASSERT(!NT_SUCCESS(Status
));
2800 if(NT_SUCCESS(Status
))
2802 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2803 *AllocBase
= Buffer
;
2804 *ReadSize
= UsedSize
- OffsetAdjustment
;
2808 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2815 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2816 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2817 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2822 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2826 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2828 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2829 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2836 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2840 MmspAssertSegmentsSorted(ImageSectionObject
);
2842 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2844 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2848 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2849 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2850 ImageSectionObject
->Segments
[i
- 1].Length
));
2858 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2862 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2864 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2865 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2873 MmspCompareSegments(const void * x
,
2876 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2877 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2880 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2881 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2885 * Ensures an image section's segments are sorted in memory
2890 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2893 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2895 MmspAssertSegmentsSorted(ImageSectionObject
);
2899 qsort(ImageSectionObject
->Segments
,
2900 ImageSectionObject
->NrSegments
,
2901 sizeof(ImageSectionObject
->Segments
[0]),
2902 MmspCompareSegments
);
2908 * Ensures an image section's segments don't overlap in memory and don't have
2909 * gaps and don't have a null size. We let them map to overlapping file regions,
2910 * though - that's not necessarily an error
2915 MmspCheckSegmentBounds
2917 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2923 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2925 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2929 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2931 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2933 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2941 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2942 * page could be OK (Windows seems to be OK with them), and larger gaps
2943 * could lead to image sections spanning several discontiguous regions
2944 * (NtMapViewOfSection could then refuse to map them, and they could
2945 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2947 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2948 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2949 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2960 * Merges and pads an image section's segments until they all are page-aligned
2961 * and have a size that is a multiple of the page size
2966 MmspPageAlignSegments
2968 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2974 BOOLEAN Initialized
;
2975 PMM_SECTION_SEGMENT EffectiveSegment
;
2977 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2979 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2983 Initialized
= FALSE
;
2985 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2987 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2990 * The first segment requires special handling
2994 ULONG_PTR VirtualAddress
;
2995 ULONG_PTR VirtualOffset
;
2997 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2999 /* Round down the virtual address to the nearest page */
3000 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3002 /* Round up the virtual size to the nearest page */
3003 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3004 EffectiveSegment
->VirtualAddress
;
3006 /* Adjust the raw address and size */
3007 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3009 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3015 * Garbage in, garbage out: unaligned base addresses make the file
3016 * offset point in curious and odd places, but that's what we were
3019 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3020 EffectiveSegment
->RawLength
+= VirtualOffset
;
3024 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3025 ULONG_PTR EndOfEffectiveSegment
;
3027 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3028 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3031 * The current segment begins exactly where the current effective
3032 * segment ended, therefore beginning a new effective segment
3034 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3037 ASSERT(LastSegment
<= i
);
3038 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3040 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3042 if (LastSegment
!= i
)
3045 * Copy the current segment. If necessary, the effective segment
3046 * will be expanded later
3048 *EffectiveSegment
= *Segment
;
3052 * Page-align the virtual size. We know for sure the virtual address
3055 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3056 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3059 * The current segment is still part of the current effective segment:
3060 * extend the effective segment to reflect this
3062 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3064 static const ULONG FlagsToProtection
[16] =
3072 PAGE_EXECUTE_READWRITE
,
3073 PAGE_EXECUTE_READWRITE
,
3078 PAGE_EXECUTE_WRITECOPY
,
3079 PAGE_EXECUTE_WRITECOPY
,
3080 PAGE_EXECUTE_WRITECOPY
,
3081 PAGE_EXECUTE_WRITECOPY
3084 unsigned ProtectionFlags
;
3087 * Extend the file size
3090 /* Unaligned segments must be contiguous within the file */
3091 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3092 EffectiveSegment
->RawLength
))
3097 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3100 * Extend the virtual size
3102 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3104 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3105 EffectiveSegment
->VirtualAddress
;
3108 * Merge the protection
3110 EffectiveSegment
->Protection
|= Segment
->Protection
;
3112 /* Clean up redundance */
3113 ProtectionFlags
= 0;
3115 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3116 ProtectionFlags
|= 1 << 0;
3118 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3119 ProtectionFlags
|= 1 << 1;
3121 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3122 ProtectionFlags
|= 1 << 2;
3124 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3125 ProtectionFlags
|= 1 << 3;
3127 ASSERT(ProtectionFlags
< 16);
3128 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3130 /* If a segment was required to be shared and cannot, fail */
3131 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3132 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3138 * We assume no holes between segments at this point
3142 KeBugCheck(MEMORY_MANAGEMENT
);
3146 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3152 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3153 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3155 LARGE_INTEGER Offset
;
3157 PVOID FileHeaderBuffer
;
3158 ULONG FileHeaderSize
;
3160 ULONG OldNrSegments
;
3165 * Read the beginning of the file (2 pages). Should be enough to contain
3166 * all (or most) of the headers
3168 Offset
.QuadPart
= 0;
3170 /* FIXME: use FileObject instead of FileHandle */
3171 Status
= ExeFmtpReadFile (FileHandle
,
3178 if (!NT_SUCCESS(Status
))
3181 if (FileHeaderSize
== 0)
3183 ExFreePool(FileHeaderBuffer
);
3184 return STATUS_UNSUCCESSFUL
;
3188 * Look for a loader that can handle this executable
3190 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3192 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3195 /* FIXME: use FileObject instead of FileHandle */
3196 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3202 ExeFmtpAllocateSegments
);
3204 if (!NT_SUCCESS(Status
))
3206 if (ImageSectionObject
->Segments
)
3208 ExFreePool(ImageSectionObject
->Segments
);
3209 ImageSectionObject
->Segments
= NULL
;
3213 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3217 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3220 * No loader handled the format
3222 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3224 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3225 ASSERT(!NT_SUCCESS(Status
));
3228 if (!NT_SUCCESS(Status
))
3231 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3236 /* FIXME? are these values platform-dependent? */
3237 if(ImageSectionObject
->StackReserve
== 0)
3238 ImageSectionObject
->StackReserve
= 0x40000;
3240 if(ImageSectionObject
->StackCommit
== 0)
3241 ImageSectionObject
->StackCommit
= 0x1000;
3243 if(ImageSectionObject
->ImageBase
== 0)
3245 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3246 ImageSectionObject
->ImageBase
= 0x10000000;
3248 ImageSectionObject
->ImageBase
= 0x00400000;
3252 * And now the fun part: fixing the segments
3255 /* Sort them by virtual address */
3256 MmspSortSegments(ImageSectionObject
, Flags
);
3258 /* Ensure they don't overlap in memory */
3259 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3260 return STATUS_INVALID_IMAGE_FORMAT
;
3262 /* Ensure they are aligned */
3263 OldNrSegments
= ImageSectionObject
->NrSegments
;
3265 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3266 return STATUS_INVALID_IMAGE_FORMAT
;
3268 /* Trim them if the alignment phase merged some of them */
3269 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3271 PMM_SECTION_SEGMENT Segments
;
3272 SIZE_T SizeOfSegments
;
3274 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3276 Segments
= ExAllocatePoolWithTag(PagedPool
,
3278 TAG_MM_SECTION_SEGMENT
);
3280 if (Segments
== NULL
)
3281 return STATUS_INSUFFICIENT_RESOURCES
;
3283 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3284 ExFreePool(ImageSectionObject
->Segments
);
3285 ImageSectionObject
->Segments
= Segments
;
3288 /* And finish their initialization */
3289 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3291 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3292 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3294 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3295 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3298 ASSERT(NT_SUCCESS(Status
));
3303 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3304 ACCESS_MASK DesiredAccess
,
3305 POBJECT_ATTRIBUTES ObjectAttributes
,
3306 PLARGE_INTEGER UMaximumSize
,
3307 ULONG SectionPageProtection
,
3308 ULONG AllocationAttributes
,
3311 PROS_SECTION_OBJECT Section
;
3313 PFILE_OBJECT FileObject
;
3314 PMM_SECTION_SEGMENT SectionSegments
;
3315 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3317 ULONG FileAccess
= 0;
3320 * Specifying a maximum size is meaningless for an image section
3322 if (UMaximumSize
!= NULL
)
3324 return(STATUS_INVALID_PARAMETER_4
);
3328 * Check file access required
3330 if (SectionPageProtection
& PAGE_READWRITE
||
3331 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3333 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3337 FileAccess
= FILE_READ_DATA
;
3341 * Reference the file handle
3343 Status
= ObReferenceObjectByHandle(FileHandle
,
3346 ExGetPreviousMode(),
3347 (PVOID
*)(PVOID
)&FileObject
,
3350 if (!NT_SUCCESS(Status
))
3356 * Create the section
3358 Status
= ObCreateObject (ExGetPreviousMode(),
3359 MmSectionObjectType
,
3361 ExGetPreviousMode(),
3363 sizeof(ROS_SECTION_OBJECT
),
3366 (PVOID
*)(PVOID
)&Section
);
3367 if (!NT_SUCCESS(Status
))
3369 ObDereferenceObject(FileObject
);
3376 Section
->SectionPageProtection
= SectionPageProtection
;
3377 Section
->AllocationAttributes
= AllocationAttributes
;
3380 * Initialized caching for this file object if previously caching
3381 * was initialized for the same on disk file
3383 Status
= CcTryToInitializeFileCache(FileObject
);
3385 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3387 NTSTATUS StatusExeFmt
;
3389 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3390 if (ImageSectionObject
== NULL
)
3392 ObDereferenceObject(FileObject
);
3393 ObDereferenceObject(Section
);
3394 return(STATUS_NO_MEMORY
);
3397 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3399 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3401 if (!NT_SUCCESS(StatusExeFmt
))
3403 if(ImageSectionObject
->Segments
!= NULL
)
3404 ExFreePool(ImageSectionObject
->Segments
);
3406 ExFreePool(ImageSectionObject
);
3407 ObDereferenceObject(Section
);
3408 ObDereferenceObject(FileObject
);
3409 return(StatusExeFmt
);
3412 Section
->ImageSection
= ImageSectionObject
;
3413 ASSERT(ImageSectionObject
->Segments
);
3418 Status
= MmspWaitForFileLock(FileObject
);
3419 if (!NT_SUCCESS(Status
))
3421 ExFreePool(ImageSectionObject
->Segments
);
3422 ExFreePool(ImageSectionObject
);
3423 ObDereferenceObject(Section
);
3424 ObDereferenceObject(FileObject
);
3428 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3429 ImageSectionObject
, NULL
))
3432 * An other thread has initialized the same image in the background
3434 ExFreePool(ImageSectionObject
->Segments
);
3435 ExFreePool(ImageSectionObject
);
3436 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3437 Section
->ImageSection
= ImageSectionObject
;
3438 SectionSegments
= ImageSectionObject
->Segments
;
3440 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3442 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3446 Status
= StatusExeFmt
;
3453 Status
= MmspWaitForFileLock(FileObject
);
3454 if (Status
!= STATUS_SUCCESS
)
3456 ObDereferenceObject(Section
);
3457 ObDereferenceObject(FileObject
);
3461 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3462 Section
->ImageSection
= ImageSectionObject
;
3463 SectionSegments
= ImageSectionObject
->Segments
;
3466 * Otherwise just reference all the section segments
3468 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3470 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3473 Status
= STATUS_SUCCESS
;
3475 Section
->FileObject
= FileObject
;
3476 CcRosReferenceCache(FileObject
);
3477 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3478 *SectionObject
= Section
;
3486 NtCreateSection (OUT PHANDLE SectionHandle
,
3487 IN ACCESS_MASK DesiredAccess
,
3488 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3489 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3490 IN ULONG SectionPageProtection OPTIONAL
,
3491 IN ULONG AllocationAttributes
,
3492 IN HANDLE FileHandle OPTIONAL
)
3494 LARGE_INTEGER SafeMaximumSize
;
3495 PVOID SectionObject
;
3496 KPROCESSOR_MODE PreviousMode
;
3497 NTSTATUS Status
= STATUS_SUCCESS
;
3499 PreviousMode
= ExGetPreviousMode();
3501 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3505 /* make a copy on the stack */
3506 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3507 MaximumSize
= &SafeMaximumSize
;
3509 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3511 Status
= _SEH2_GetExceptionCode();
3515 if(!NT_SUCCESS(Status
))
3521 Status
= MmCreateSection(&SectionObject
,
3525 SectionPageProtection
,
3526 AllocationAttributes
,
3529 if (NT_SUCCESS(Status
))
3531 Status
= ObInsertObject ((PVOID
)SectionObject
,
3543 /**********************************************************************
3561 NtOpenSection(PHANDLE SectionHandle
,
3562 ACCESS_MASK DesiredAccess
,
3563 POBJECT_ATTRIBUTES ObjectAttributes
)
3566 KPROCESSOR_MODE PreviousMode
;
3567 NTSTATUS Status
= STATUS_SUCCESS
;
3569 PreviousMode
= ExGetPreviousMode();
3571 if(PreviousMode
!= KernelMode
)
3575 ProbeForWriteHandle(SectionHandle
);
3577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3579 Status
= _SEH2_GetExceptionCode();
3583 if(!NT_SUCCESS(Status
))
3589 Status
= ObOpenObjectByName(ObjectAttributes
,
3590 MmSectionObjectType
,
3597 if(NT_SUCCESS(Status
))
3601 *SectionHandle
= hSection
;
3603 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3605 Status
= _SEH2_GetExceptionCode();
3614 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3615 PROS_SECTION_OBJECT Section
,
3616 PMM_SECTION_SEGMENT Segment
,
3621 ULONG AllocationType
)
3625 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3627 BoundaryAddressMultiple
.QuadPart
= 0;
3629 Status
= MmCreateMemoryArea(AddressSpace
,
3630 MEMORY_AREA_SECTION_VIEW
,
3637 BoundaryAddressMultiple
);
3638 if (!NT_SUCCESS(Status
))
3640 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3641 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3645 ObReferenceObject((PVOID
)Section
);
3647 MArea
->Data
.SectionData
.Segment
= Segment
;
3648 MArea
->Data
.SectionData
.Section
= Section
;
3649 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3650 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3651 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3652 ViewSize
, 0, Protect
);
3654 return(STATUS_SUCCESS
);
3658 /**********************************************************************
3660 * NtMapViewOfSection
3663 * Maps a view of a section into the virtual address space of a
3668 * Handle of the section.
3671 * Handle of the process.
3674 * Desired base address (or NULL) on entry;
3675 * Actual base address of the view on exit.
3678 * Number of high order address bits that must be zero.
3681 * Size in bytes of the initially committed section of
3685 * Offset in bytes from the beginning of the section
3686 * to the beginning of the view.
3689 * Desired length of map (or zero to map all) on entry
3690 * Actual length mapped on exit.
3692 * InheritDisposition
3693 * Specified how the view is to be shared with
3697 * Type of allocation for the pages.
3700 * Protection for the committed region of the view.
3708 NtMapViewOfSection(IN HANDLE SectionHandle
,
3709 IN HANDLE ProcessHandle
,
3710 IN OUT PVOID
* BaseAddress OPTIONAL
,
3711 IN ULONG_PTR ZeroBits OPTIONAL
,
3712 IN SIZE_T CommitSize
,
3713 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3714 IN OUT PSIZE_T ViewSize
,
3715 IN SECTION_INHERIT InheritDisposition
,
3716 IN ULONG AllocationType OPTIONAL
,
3719 PVOID SafeBaseAddress
;
3720 LARGE_INTEGER SafeSectionOffset
;
3721 SIZE_T SafeViewSize
;
3722 PROS_SECTION_OBJECT Section
;
3724 KPROCESSOR_MODE PreviousMode
;
3725 PMMSUPPORT AddressSpace
;
3726 NTSTATUS Status
= STATUS_SUCCESS
;
3730 * Check the protection
3732 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3734 return STATUS_INVALID_PARAMETER_10
;
3737 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3738 if (tmpProtect
!= PAGE_NOACCESS
&&
3739 tmpProtect
!= PAGE_READONLY
&&
3740 tmpProtect
!= PAGE_READWRITE
&&
3741 tmpProtect
!= PAGE_WRITECOPY
&&
3742 tmpProtect
!= PAGE_EXECUTE
&&
3743 tmpProtect
!= PAGE_EXECUTE_READ
&&
3744 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3745 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3747 return STATUS_INVALID_PAGE_PROTECTION
;
3750 PreviousMode
= ExGetPreviousMode();
3752 if(PreviousMode
!= KernelMode
)
3754 SafeBaseAddress
= NULL
;
3755 SafeSectionOffset
.QuadPart
= 0;
3760 if(BaseAddress
!= NULL
)
3762 ProbeForWritePointer(BaseAddress
);
3763 SafeBaseAddress
= *BaseAddress
;
3765 if(SectionOffset
!= NULL
)
3767 ProbeForWriteLargeInteger(SectionOffset
);
3768 SafeSectionOffset
= *SectionOffset
;
3770 ProbeForWriteSize_t(ViewSize
);
3771 SafeViewSize
= *ViewSize
;
3773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3775 Status
= _SEH2_GetExceptionCode();
3779 if(!NT_SUCCESS(Status
))
3786 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3787 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3788 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3791 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3793 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3794 PROCESS_VM_OPERATION
,
3797 (PVOID
*)(PVOID
)&Process
,
3799 if (!NT_SUCCESS(Status
))
3804 AddressSpace
= &Process
->Vm
;
3806 Status
= ObReferenceObjectByHandle(SectionHandle
,
3808 MmSectionObjectType
,
3810 (PVOID
*)(PVOID
)&Section
,
3812 if (!(NT_SUCCESS(Status
)))
3814 DPRINT("ObReference failed rc=%x\n",Status
);
3815 ObDereferenceObject(Process
);
3819 Status
= MmMapViewOfSection(Section
,
3821 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3824 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3825 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3830 /* Check if this is an image for the current process */
3831 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3832 (Process
== PsGetCurrentProcess()) &&
3833 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3835 /* Notify the debugger */
3836 DbgkMapViewOfSection(Section
,
3838 SafeSectionOffset
.LowPart
,
3842 ObDereferenceObject(Section
);
3843 ObDereferenceObject(Process
);
3845 if(NT_SUCCESS(Status
))
3847 /* copy parameters back to the caller */
3850 if(BaseAddress
!= NULL
)
3852 *BaseAddress
= SafeBaseAddress
;
3854 if(SectionOffset
!= NULL
)
3856 *SectionOffset
= SafeSectionOffset
;
3858 if(ViewSize
!= NULL
)
3860 *ViewSize
= SafeViewSize
;
3863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3865 Status
= _SEH2_GetExceptionCode();
3874 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3875 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3878 PFILE_OBJECT FileObject
;
3881 SWAPENTRY SavedSwapEntry
;
3884 PROS_SECTION_OBJECT Section
;
3885 PMM_SECTION_SEGMENT Segment
;
3886 PMMSUPPORT AddressSpace
;
3889 AddressSpace
= (PMMSUPPORT
)Context
;
3890 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3892 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3894 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3895 MemoryArea
->Data
.SectionData
.ViewOffset
;
3897 Section
= MemoryArea
->Data
.SectionData
.Section
;
3898 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3900 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3904 MmUnlockSectionSegment(Segment
);
3905 MmUnlockAddressSpace(AddressSpace
);
3907 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3908 if (Status
!= STATUS_SUCCESS
)
3910 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3911 KeBugCheck(MEMORY_MANAGEMENT
);
3914 MmLockAddressSpace(AddressSpace
);
3915 MmLockSectionSegment(Segment
);
3916 MmspCompleteAndReleasePageOp(PageOp
);
3917 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3920 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3923 * For a dirty, datafile, non-private page mark it as dirty in the
3926 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3928 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3930 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3931 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3932 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3933 ASSERT(SwapEntry
== 0);
3942 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3944 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3945 KeBugCheck(MEMORY_MANAGEMENT
);
3947 MmFreeSwapPage(SwapEntry
);
3951 if (IS_SWAP_FROM_SSE(Entry
) ||
3952 Page
!= PFN_FROM_SSE(Entry
))
3957 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3959 DPRINT1("Found a private page in a pagefile section.\n");
3960 KeBugCheck(MEMORY_MANAGEMENT
);
3963 * Just dereference private pages
3965 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3966 if (SavedSwapEntry
!= 0)
3968 MmFreeSwapPage(SavedSwapEntry
);
3969 MmSetSavedSwapEntryPage(Page
, 0);
3971 MmDeleteRmap(Page
, Process
, Address
);
3972 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3976 MmDeleteRmap(Page
, Process
, Address
);
3977 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3983 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3987 PMEMORY_AREA MemoryArea
;
3988 PROS_SECTION_OBJECT Section
;
3989 PMM_SECTION_SEGMENT Segment
;
3990 PLIST_ENTRY CurrentEntry
;
3991 PMM_REGION CurrentRegion
;
3992 PLIST_ENTRY RegionListHead
;
3994 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3996 if (MemoryArea
== NULL
)
3998 return(STATUS_UNSUCCESSFUL
);
4001 MemoryArea
->DeleteInProgress
= TRUE
;
4002 Section
= MemoryArea
->Data
.SectionData
.Section
;
4003 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4005 MmLockSectionSegment(Segment
);
4007 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4008 while (!IsListEmpty(RegionListHead
))
4010 CurrentEntry
= RemoveHeadList(RegionListHead
);
4011 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4012 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4015 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4017 Status
= MmFreeMemoryArea(AddressSpace
,
4024 Status
= MmFreeMemoryArea(AddressSpace
,
4029 MmUnlockSectionSegment(Segment
);
4030 ObDereferenceObject(Section
);
4031 return(STATUS_SUCCESS
);
4038 MmUnmapViewOfSection(PEPROCESS Process
,
4042 PMEMORY_AREA MemoryArea
;
4043 PMMSUPPORT AddressSpace
;
4044 PROS_SECTION_OBJECT Section
;
4047 PVOID ImageBaseAddress
= 0;
4049 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4050 Process
, BaseAddress
);
4054 AddressSpace
= &Process
->Vm
;
4056 MmLockAddressSpace(AddressSpace
);
4057 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4059 if (MemoryArea
== NULL
||
4060 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4061 MemoryArea
->DeleteInProgress
)
4063 MmUnlockAddressSpace(AddressSpace
);
4064 return STATUS_NOT_MAPPED_VIEW
;
4067 MemoryArea
->DeleteInProgress
= TRUE
;
4069 while (MemoryArea
->PageOpCount
)
4071 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4075 Offset
-= PAGE_SIZE
;
4076 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4077 MemoryArea
->Data
.SectionData
.Segment
,
4078 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4081 MmUnlockAddressSpace(AddressSpace
);
4082 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4083 if (Status
!= STATUS_SUCCESS
)
4085 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4086 KeBugCheck(MEMORY_MANAGEMENT
);
4088 MmLockAddressSpace(AddressSpace
);
4089 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4091 if (MemoryArea
== NULL
||
4092 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4094 MmUnlockAddressSpace(AddressSpace
);
4095 return STATUS_NOT_MAPPED_VIEW
;
4102 Section
= MemoryArea
->Data
.SectionData
.Section
;
4104 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4108 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4109 PMM_SECTION_SEGMENT SectionSegments
;
4110 PMM_SECTION_SEGMENT Segment
;
4112 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4113 ImageSectionObject
= Section
->ImageSection
;
4114 SectionSegments
= ImageSectionObject
->Segments
;
4115 NrSegments
= ImageSectionObject
->NrSegments
;
4117 /* Search for the current segment within the section segments
4118 * and calculate the image base address */
4119 for (i
= 0; i
< NrSegments
; i
++)
4121 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4123 if (Segment
== &SectionSegments
[i
])
4125 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4130 if (i
>= NrSegments
)
4132 KeBugCheck(MEMORY_MANAGEMENT
);
4135 for (i
= 0; i
< NrSegments
; i
++)
4137 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4139 PVOID SBaseAddress
= (PVOID
)
4140 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4142 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4148 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4151 /* Notify debugger */
4152 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4154 MmUnlockAddressSpace(AddressSpace
);
4155 return(STATUS_SUCCESS
);
4158 /**********************************************************************
4160 * NtUnmapViewOfSection
4175 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4179 KPROCESSOR_MODE PreviousMode
;
4182 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4183 ProcessHandle
, BaseAddress
);
4185 PreviousMode
= ExGetPreviousMode();
4187 DPRINT("Referencing process\n");
4188 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4189 PROCESS_VM_OPERATION
,
4192 (PVOID
*)(PVOID
)&Process
,
4194 if (!NT_SUCCESS(Status
))
4196 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4200 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4202 ObDereferenceObject(Process
);
4209 * Queries the information of a section object.
4211 * @param SectionHandle
4212 * Handle to the section object. It must be opened with SECTION_QUERY
4214 * @param SectionInformationClass
4215 * Index to a certain information structure. Can be either
4216 * SectionBasicInformation or SectionImageInformation. The latter
4217 * is valid only for sections that were created with the SEC_IMAGE
4219 * @param SectionInformation
4220 * Caller supplies storage for resulting information.
4222 * Size of the supplied storage.
4223 * @param ResultLength
4231 NtQuerySection(IN HANDLE SectionHandle
,
4232 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4233 OUT PVOID SectionInformation
,
4234 IN ULONG SectionInformationLength
,
4235 OUT PULONG ResultLength OPTIONAL
)
4237 PROS_SECTION_OBJECT Section
;
4238 KPROCESSOR_MODE PreviousMode
;
4239 NTSTATUS Status
= STATUS_SUCCESS
;
4241 PreviousMode
= ExGetPreviousMode();
4243 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4245 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4247 SectionInformationLength
,
4251 if(!NT_SUCCESS(Status
))
4253 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4257 Status
= ObReferenceObjectByHandle(SectionHandle
,
4259 MmSectionObjectType
,
4261 (PVOID
*)(PVOID
)&Section
,
4263 if (NT_SUCCESS(Status
))
4265 switch (SectionInformationClass
)
4267 case SectionBasicInformation
:
4269 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4273 Sbi
->Attributes
= Section
->AllocationAttributes
;
4274 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4276 Sbi
->BaseAddress
= 0;
4277 Sbi
->Size
.QuadPart
= 0;
4281 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4282 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4285 if (ResultLength
!= NULL
)
4287 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4289 Status
= STATUS_SUCCESS
;
4291 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4293 Status
= _SEH2_GetExceptionCode();
4300 case SectionImageInformation
:
4302 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4306 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4307 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4309 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4310 ImageSectionObject
= Section
->ImageSection
;
4312 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4313 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4314 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4315 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4316 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4317 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4318 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4319 Sii
->Machine
= ImageSectionObject
->Machine
;
4320 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4323 if (ResultLength
!= NULL
)
4325 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4327 Status
= STATUS_SUCCESS
;
4329 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4331 Status
= _SEH2_GetExceptionCode();
4339 ObDereferenceObject(Section
);
4347 * Extends size of file backed section.
4349 * @param SectionHandle
4350 * Handle to the section object. It must be opened with
4351 * SECTION_EXTEND_SIZE access.
4352 * @param NewMaximumSize
4353 * New maximum size of the section in bytes.
4357 * @todo Move the actual code to internal function MmExtendSection.
4361 NtExtendSection(IN HANDLE SectionHandle
,
4362 IN PLARGE_INTEGER NewMaximumSize
)
4364 LARGE_INTEGER SafeNewMaximumSize
;
4365 PROS_SECTION_OBJECT Section
;
4366 KPROCESSOR_MODE PreviousMode
;
4367 NTSTATUS Status
= STATUS_SUCCESS
;
4369 PreviousMode
= ExGetPreviousMode();
4371 if(PreviousMode
!= KernelMode
)
4375 /* make a copy on the stack */
4376 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4377 NewMaximumSize
= &SafeNewMaximumSize
;
4379 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4381 Status
= _SEH2_GetExceptionCode();
4385 if(!NT_SUCCESS(Status
))
4391 Status
= ObReferenceObjectByHandle(SectionHandle
,
4392 SECTION_EXTEND_SIZE
,
4393 MmSectionObjectType
,
4397 if (!NT_SUCCESS(Status
))
4402 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4404 ObfDereferenceObject(Section
);
4405 return STATUS_INVALID_PARAMETER
;
4409 * - Acquire file extneding resource.
4410 * - Check if we're not resizing the section below it's actual size!
4411 * - Extend segments if needed.
4412 * - Set file information (FileAllocationInformation) to the new size.
4413 * - Release file extending resource.
4416 ObDereferenceObject(Section
);
4418 return STATUS_NOT_IMPLEMENTED
;
4422 /**********************************************************************
4424 * MmAllocateSection@4
4434 * Code taken from ntoskrnl/mm/special.c.
4439 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4444 PMMSUPPORT AddressSpace
;
4445 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4447 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4449 BoundaryAddressMultiple
.QuadPart
= 0;
4451 AddressSpace
= MmGetKernelAddressSpace();
4452 Result
= BaseAddress
;
4453 MmLockAddressSpace(AddressSpace
);
4454 Status
= MmCreateMemoryArea (AddressSpace
,
4462 BoundaryAddressMultiple
);
4463 MmUnlockAddressSpace(AddressSpace
);
4465 if (!NT_SUCCESS(Status
))
4469 DPRINT("Result %p\n",Result
);
4471 /* Create a virtual mapping for this memory area */
4472 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4474 return ((PVOID
)Result
);
4478 /**********************************************************************
4480 * MmMapViewOfSection
4483 * Maps a view of a section into the virtual address space of a
4488 * Pointer to the section object.
4491 * Pointer to the process.
4494 * Desired base address (or NULL) on entry;
4495 * Actual base address of the view on exit.
4498 * Number of high order address bits that must be zero.
4501 * Size in bytes of the initially committed section of
4505 * Offset in bytes from the beginning of the section
4506 * to the beginning of the view.
4509 * Desired length of map (or zero to map all) on entry
4510 * Actual length mapped on exit.
4512 * InheritDisposition
4513 * Specified how the view is to be shared with
4517 * Type of allocation for the pages.
4520 * Protection for the committed region of the view.
4528 MmMapViewOfSection(IN PVOID SectionObject
,
4529 IN PEPROCESS Process
,
4530 IN OUT PVOID
*BaseAddress
,
4531 IN ULONG_PTR ZeroBits
,
4532 IN SIZE_T CommitSize
,
4533 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4534 IN OUT PSIZE_T ViewSize
,
4535 IN SECTION_INHERIT InheritDisposition
,
4536 IN ULONG AllocationType
,
4539 PROS_SECTION_OBJECT Section
;
4540 PMMSUPPORT AddressSpace
;
4542 NTSTATUS Status
= STATUS_SUCCESS
;
4546 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4548 return STATUS_INVALID_PAGE_PROTECTION
;
4552 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4553 AddressSpace
= &Process
->Vm
;
4555 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4557 MmLockAddressSpace(AddressSpace
);
4559 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4563 ULONG_PTR ImageBase
;
4565 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4566 PMM_SECTION_SEGMENT SectionSegments
;
4568 ImageSectionObject
= Section
->ImageSection
;
4569 SectionSegments
= ImageSectionObject
->Segments
;
4570 NrSegments
= ImageSectionObject
->NrSegments
;
4573 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4576 ImageBase
= ImageSectionObject
->ImageBase
;
4580 for (i
= 0; i
< NrSegments
; i
++)
4582 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4584 ULONG_PTR MaxExtent
;
4585 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4586 SectionSegments
[i
].Length
;
4587 ImageSize
= max(ImageSize
, MaxExtent
);
4591 ImageSectionObject
->ImageSize
= ImageSize
;
4593 /* Check there is enough space to map the section at that point. */
4594 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4595 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4597 /* Fail if the user requested a fixed base address. */
4598 if ((*BaseAddress
) != NULL
)
4600 MmUnlockAddressSpace(AddressSpace
);
4601 return(STATUS_UNSUCCESSFUL
);
4603 /* Otherwise find a gap to map the image. */
4604 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4607 MmUnlockAddressSpace(AddressSpace
);
4608 return(STATUS_UNSUCCESSFUL
);
4612 for (i
= 0; i
< NrSegments
; i
++)
4614 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4616 PVOID SBaseAddress
= (PVOID
)
4617 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4618 MmLockSectionSegment(&SectionSegments
[i
]);
4619 Status
= MmMapViewOfSegment(AddressSpace
,
4621 &SectionSegments
[i
],
4623 SectionSegments
[i
].Length
,
4624 SectionSegments
[i
].Protection
,
4627 MmUnlockSectionSegment(&SectionSegments
[i
]);
4628 if (!NT_SUCCESS(Status
))
4630 MmUnlockAddressSpace(AddressSpace
);
4636 *BaseAddress
= (PVOID
)ImageBase
;
4640 /* check for write access */
4641 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4642 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4644 MmUnlockAddressSpace(AddressSpace
);
4645 return STATUS_SECTION_PROTECTION
;
4647 /* check for read access */
4648 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4649 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4651 MmUnlockAddressSpace(AddressSpace
);
4652 return STATUS_SECTION_PROTECTION
;
4654 /* check for execute access */
4655 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4656 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4658 MmUnlockAddressSpace(AddressSpace
);
4659 return STATUS_SECTION_PROTECTION
;
4662 if (ViewSize
== NULL
)
4664 /* Following this pointer would lead to us to the dark side */
4665 /* What to do? Bugcheck? Return status? Do the mambo? */
4666 KeBugCheck(MEMORY_MANAGEMENT
);
4669 if (SectionOffset
== NULL
)
4675 ViewOffset
= SectionOffset
->u
.LowPart
;
4678 if ((ViewOffset
% PAGE_SIZE
) != 0)
4680 MmUnlockAddressSpace(AddressSpace
);
4681 return(STATUS_MAPPED_ALIGNMENT
);
4684 if ((*ViewSize
) == 0)
4686 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4688 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4690 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4693 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4695 MmLockSectionSegment(Section
->Segment
);
4696 Status
= MmMapViewOfSegment(AddressSpace
,
4703 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4704 MmUnlockSectionSegment(Section
->Segment
);
4705 if (!NT_SUCCESS(Status
))
4707 MmUnlockAddressSpace(AddressSpace
);
4712 MmUnlockAddressSpace(AddressSpace
);
4714 return(STATUS_SUCCESS
);
4721 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4722 IN PLARGE_INTEGER NewFileSize
)
4724 /* Check whether an ImageSectionObject exists */
4725 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4727 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4731 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4733 PMM_SECTION_SEGMENT Segment
;
4735 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4738 if (Segment
->ReferenceCount
!= 0)
4740 /* Check size of file */
4741 if (SectionObjectPointer
->SharedCacheMap
)
4743 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4744 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4752 /* Something must gone wrong
4753 * how can we have a Section but no
4755 DPRINT1("ERROR: DataSectionObject without reference!\n");
4759 DPRINT("FIXME: didn't check for outstanding write probes\n");
4769 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4779 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4780 IN MMFLUSH_TYPE FlushType
)
4784 case MmFlushForDelete
:
4785 if (SectionObjectPointer
->ImageSectionObject
||
4786 SectionObjectPointer
->DataSectionObject
)
4790 CcRosSetRemoveOnClose(SectionObjectPointer
);
4792 case MmFlushForWrite
:
4802 MmForceSectionClosed (
4803 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4804 IN BOOLEAN DelayClose
)
4815 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4816 OUT PVOID
* MappedBase
,
4817 IN OUT PULONG ViewSize
)
4819 PROS_SECTION_OBJECT Section
;
4820 PMMSUPPORT AddressSpace
;
4823 DPRINT("MmMapViewInSystemSpace() called\n");
4825 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4826 AddressSpace
= MmGetKernelAddressSpace();
4828 MmLockAddressSpace(AddressSpace
);
4831 if ((*ViewSize
) == 0)
4833 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4835 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4837 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4840 MmLockSectionSegment(Section
->Segment
);
4843 Status
= MmMapViewOfSegment(AddressSpace
,
4852 MmUnlockSectionSegment(Section
->Segment
);
4853 MmUnlockAddressSpace(AddressSpace
);
4863 MmMapViewInSessionSpace (
4865 OUT PVOID
*MappedBase
,
4866 IN OUT PSIZE_T ViewSize
4870 return STATUS_NOT_IMPLEMENTED
;
4878 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4880 PMMSUPPORT AddressSpace
;
4883 DPRINT("MmUnmapViewInSystemSpace() called\n");
4885 AddressSpace
= MmGetKernelAddressSpace();
4887 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4897 MmUnmapViewInSessionSpace (
4902 return STATUS_NOT_IMPLEMENTED
;
4909 MmSetBankedSection (ULONG Unknown0
,
4917 return (STATUS_NOT_IMPLEMENTED
);
4921 /**********************************************************************
4926 * Creates a section object.
4929 * SectionObject (OUT)
4930 * Caller supplied storage for the resulting pointer
4931 * to a SECTION_OBJECT instance;
4934 * Specifies the desired access to the section can be a
4936 * STANDARD_RIGHTS_REQUIRED |
4938 * SECTION_MAP_WRITE |
4939 * SECTION_MAP_READ |
4940 * SECTION_MAP_EXECUTE
4942 * ObjectAttributes [OPTIONAL]
4943 * Initialized attributes for the object can be used
4944 * to create a named section;
4947 * Maximizes the size of the memory section. Must be
4948 * non-NULL for a page-file backed section.
4949 * If value specified for a mapped file and the file is
4950 * not large enough, file will be extended.
4952 * SectionPageProtection
4953 * Can be a combination of:
4959 * AllocationAttributes
4960 * Can be a combination of:
4965 * Handle to a file to create a section mapped to a file
4966 * instead of a memory backed section;
4977 MmCreateSection (OUT PVOID
* Section
,
4978 IN ACCESS_MASK DesiredAccess
,
4979 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4980 IN PLARGE_INTEGER MaximumSize
,
4981 IN ULONG SectionPageProtection
,
4982 IN ULONG AllocationAttributes
,
4983 IN HANDLE FileHandle OPTIONAL
,
4984 IN PFILE_OBJECT File OPTIONAL
)
4987 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4990 * Check the protection
4992 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4993 if (Protection
!= PAGE_NOACCESS
&&
4994 Protection
!= PAGE_READONLY
&&
4995 Protection
!= PAGE_READWRITE
&&
4996 Protection
!= PAGE_WRITECOPY
&&
4997 Protection
!= PAGE_EXECUTE
&&
4998 Protection
!= PAGE_EXECUTE_READ
&&
4999 Protection
!= PAGE_EXECUTE_READWRITE
&&
5000 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5002 return STATUS_INVALID_PAGE_PROTECTION
;
5005 if (AllocationAttributes
& SEC_IMAGE
)
5007 return(MmCreateImageSection(SectionObject
,
5011 SectionPageProtection
,
5012 AllocationAttributes
,
5016 if (FileHandle
!= NULL
)
5018 return(MmCreateDataFileSection(SectionObject
,
5022 SectionPageProtection
,
5023 AllocationAttributes
,
5027 return(MmCreatePageFileSection(SectionObject
,
5031 SectionPageProtection
,
5032 AllocationAttributes
));
5037 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5038 IN OUT PULONG_PTR NumberOfPages
,
5039 IN OUT PULONG_PTR UserPfnArray
)
5042 return STATUS_NOT_IMPLEMENTED
;
5047 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5048 IN ULONG_PTR NumberOfPages
,
5049 IN OUT PULONG_PTR UserPfnArray
)
5052 return STATUS_NOT_IMPLEMENTED
;
5057 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5058 IN ULONG_PTR NumberOfPages
,
5059 IN OUT PULONG_PTR UserPfnArray
)
5062 return STATUS_NOT_IMPLEMENTED
;
5067 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5068 IN OUT PULONG_PTR NumberOfPages
,
5069 IN OUT PULONG_PTR UserPfnArray
)
5072 return STATUS_NOT_IMPLEMENTED
;
5077 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5078 IN PVOID File2MappedAsFile
)
5081 return STATUS_NOT_IMPLEMENTED
;