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
))
2380 Section
->SectionPageProtection
= SectionPageProtection
;
2381 Section
->AllocationAttributes
= AllocationAttributes
;
2382 Section
->Segment
= NULL
;
2383 Section
->FileObject
= NULL
;
2384 Section
->MaximumSize
= MaximumSize
;
2385 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2386 TAG_MM_SECTION_SEGMENT
);
2387 if (Segment
== NULL
)
2389 ObDereferenceObject(Section
);
2390 return(STATUS_NO_MEMORY
);
2392 Section
->Segment
= Segment
;
2393 Segment
->ReferenceCount
= 1;
2394 ExInitializeFastMutex(&Segment
->Lock
);
2395 Segment
->FileOffset
= 0;
2396 Segment
->Protection
= SectionPageProtection
;
2397 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2398 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2399 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2400 Segment
->WriteCopy
= FALSE
;
2401 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2402 Segment
->VirtualAddress
= 0;
2403 Segment
->Characteristics
= 0;
2404 *SectionObject
= Section
;
2405 return(STATUS_SUCCESS
);
2411 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2412 ACCESS_MASK DesiredAccess
,
2413 POBJECT_ATTRIBUTES ObjectAttributes
,
2414 PLARGE_INTEGER UMaximumSize
,
2415 ULONG SectionPageProtection
,
2416 ULONG AllocationAttributes
,
2419 * Create a section backed by a data file
2422 PROS_SECTION_OBJECT Section
;
2424 LARGE_INTEGER MaximumSize
;
2425 PFILE_OBJECT FileObject
;
2426 PMM_SECTION_SEGMENT Segment
;
2428 IO_STATUS_BLOCK Iosb
;
2429 LARGE_INTEGER Offset
;
2431 FILE_STANDARD_INFORMATION FileInfo
;
2434 * Create the section
2436 Status
= ObCreateObject(ExGetPreviousMode(),
2437 MmSectionObjectType
,
2439 ExGetPreviousMode(),
2441 sizeof(ROS_SECTION_OBJECT
),
2444 (PVOID
*)(PVOID
)&Section
);
2445 if (!NT_SUCCESS(Status
))
2454 Section
->SectionPageProtection
= SectionPageProtection
;
2455 Section
->AllocationAttributes
= AllocationAttributes
;
2456 Section
->Segment
= NULL
;
2459 * Check file access required
2461 if (SectionPageProtection
& PAGE_READWRITE
||
2462 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2464 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2468 FileAccess
= FILE_READ_DATA
;
2472 * Reference the file handle
2474 Status
= ObReferenceObjectByHandle(FileHandle
,
2477 ExGetPreviousMode(),
2478 (PVOID
*)(PVOID
)&FileObject
,
2480 if (!NT_SUCCESS(Status
))
2482 ObDereferenceObject(Section
);
2487 * FIXME: This is propably not entirely correct. We can't look into
2488 * the standard FCB header because it might not be initialized yet
2489 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2490 * standard file information is filled on first request).
2492 Status
= IoQueryFileInformation(FileObject
,
2493 FileStandardInformation
,
2494 sizeof(FILE_STANDARD_INFORMATION
),
2497 if (!NT_SUCCESS(Status
))
2499 ObDereferenceObject(Section
);
2500 ObDereferenceObject(FileObject
);
2505 * FIXME: Revise this once a locking order for file size changes is
2508 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2510 MaximumSize
= *UMaximumSize
;
2514 MaximumSize
= FileInfo
.EndOfFile
;
2515 /* Mapping zero-sized files isn't allowed. */
2516 if (MaximumSize
.QuadPart
== 0)
2518 ObDereferenceObject(Section
);
2519 ObDereferenceObject(FileObject
);
2520 return STATUS_FILE_INVALID
;
2524 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2526 Status
= IoSetInformation(FileObject
,
2527 FileAllocationInformation
,
2528 sizeof(LARGE_INTEGER
),
2530 if (!NT_SUCCESS(Status
))
2532 ObDereferenceObject(Section
);
2533 ObDereferenceObject(FileObject
);
2534 return(STATUS_SECTION_NOT_EXTENDED
);
2538 if (FileObject
->SectionObjectPointer
== NULL
||
2539 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2542 * Read a bit so caching is initiated for the file object.
2543 * This is only needed because MiReadPage currently cannot
2544 * handle non-cached streams.
2546 Offset
.QuadPart
= 0;
2547 Status
= ZwReadFile(FileHandle
,
2556 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2558 ObDereferenceObject(Section
);
2559 ObDereferenceObject(FileObject
);
2562 if (FileObject
->SectionObjectPointer
== NULL
||
2563 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2565 /* FIXME: handle this situation */
2566 ObDereferenceObject(Section
);
2567 ObDereferenceObject(FileObject
);
2568 return STATUS_INVALID_PARAMETER
;
2575 Status
= MmspWaitForFileLock(FileObject
);
2576 if (Status
!= STATUS_SUCCESS
)
2578 ObDereferenceObject(Section
);
2579 ObDereferenceObject(FileObject
);
2584 * If this file hasn't been mapped as a data file before then allocate a
2585 * section segment to describe the data file mapping
2587 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2589 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2590 TAG_MM_SECTION_SEGMENT
);
2591 if (Segment
== NULL
)
2593 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2594 ObDereferenceObject(Section
);
2595 ObDereferenceObject(FileObject
);
2596 return(STATUS_NO_MEMORY
);
2598 Section
->Segment
= Segment
;
2599 Segment
->ReferenceCount
= 1;
2600 ExInitializeFastMutex(&Segment
->Lock
);
2602 * Set the lock before assigning the segment to the file object
2604 ExAcquireFastMutex(&Segment
->Lock
);
2605 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2607 Segment
->FileOffset
= 0;
2608 Segment
->Protection
= SectionPageProtection
;
2609 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2610 Segment
->Characteristics
= 0;
2611 Segment
->WriteCopy
= FALSE
;
2612 if (AllocationAttributes
& SEC_RESERVE
)
2614 Segment
->Length
= Segment
->RawLength
= 0;
2618 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2619 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2621 Segment
->VirtualAddress
= 0;
2622 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2627 * If the file is already mapped as a data file then we may need
2631 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2633 Section
->Segment
= Segment
;
2634 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2635 MmLockSectionSegment(Segment
);
2637 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2638 !(AllocationAttributes
& SEC_RESERVE
))
2640 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2641 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2644 MmUnlockSectionSegment(Segment
);
2645 Section
->FileObject
= FileObject
;
2646 Section
->MaximumSize
= MaximumSize
;
2647 CcRosReferenceCache(FileObject
);
2648 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2649 *SectionObject
= Section
;
2650 return(STATUS_SUCCESS
);
2654 TODO: not that great (declaring loaders statically, having to declare all of
2655 them, having to keep them extern, etc.), will fix in the future
2657 extern NTSTATUS NTAPI PeFmtCreateSection
2659 IN CONST VOID
* FileHeader
,
2660 IN SIZE_T FileHeaderSize
,
2662 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2664 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2665 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2668 extern NTSTATUS NTAPI ElfFmtCreateSection
2670 IN CONST VOID
* FileHeader
,
2671 IN SIZE_T FileHeaderSize
,
2673 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2675 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2676 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2679 /* TODO: this is a standard DDK/PSDK macro */
2680 #ifndef RTL_NUMBER_OF
2681 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2684 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2695 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2697 SIZE_T SizeOfSegments
;
2698 PMM_SECTION_SEGMENT Segments
;
2700 /* TODO: check for integer overflow */
2701 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2703 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2705 TAG_MM_SECTION_SEGMENT
);
2708 RtlZeroMemory(Segments
, SizeOfSegments
);
2716 ExeFmtpReadFile(IN PVOID File
,
2717 IN PLARGE_INTEGER Offset
,
2720 OUT PVOID
* AllocBase
,
2721 OUT PULONG ReadSize
)
2724 LARGE_INTEGER FileOffset
;
2726 ULONG OffsetAdjustment
;
2731 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2735 KeBugCheck(MEMORY_MANAGEMENT
);
2738 FileOffset
= *Offset
;
2740 /* Negative/special offset: it cannot be used in this context */
2741 if(FileOffset
.u
.HighPart
< 0)
2743 KeBugCheck(MEMORY_MANAGEMENT
);
2746 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2747 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2748 FileOffset
.u
.LowPart
= AdjustOffset
;
2750 BufferSize
= Length
+ OffsetAdjustment
;
2751 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2754 * It's ok to use paged pool, because this is a temporary buffer only used in
2755 * the loading of executables. The assumption is that MmCreateSection is
2756 * always called at low IRQLs and that these buffers don't survive a brief
2757 * initialization phase
2759 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2761 TAG('M', 'm', 'X', 'r'));
2766 Status
= MmspPageRead(File
,
2773 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2774 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2775 * to initialize internal state is even worse. Our cache manager is in need of
2779 IO_STATUS_BLOCK Iosb
;
2781 Status
= ZwReadFile(File
,
2791 if(NT_SUCCESS(Status
))
2793 UsedSize
= Iosb
.Information
;
2798 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2800 Status
= STATUS_IN_PAGE_ERROR
;
2801 ASSERT(!NT_SUCCESS(Status
));
2804 if(NT_SUCCESS(Status
))
2806 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2807 *AllocBase
= Buffer
;
2808 *ReadSize
= UsedSize
- OffsetAdjustment
;
2812 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2819 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2820 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2821 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2826 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2830 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2832 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2833 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2840 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2844 MmspAssertSegmentsSorted(ImageSectionObject
);
2846 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2848 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2852 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2853 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2854 ImageSectionObject
->Segments
[i
- 1].Length
));
2862 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2866 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2868 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2869 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2877 MmspCompareSegments(const void * x
,
2880 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2881 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2884 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2885 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2889 * Ensures an image section's segments are sorted in memory
2894 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2897 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2899 MmspAssertSegmentsSorted(ImageSectionObject
);
2903 qsort(ImageSectionObject
->Segments
,
2904 ImageSectionObject
->NrSegments
,
2905 sizeof(ImageSectionObject
->Segments
[0]),
2906 MmspCompareSegments
);
2912 * Ensures an image section's segments don't overlap in memory and don't have
2913 * gaps and don't have a null size. We let them map to overlapping file regions,
2914 * though - that's not necessarily an error
2919 MmspCheckSegmentBounds
2921 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2927 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2929 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2933 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2935 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2937 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2945 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2946 * page could be OK (Windows seems to be OK with them), and larger gaps
2947 * could lead to image sections spanning several discontiguous regions
2948 * (NtMapViewOfSection could then refuse to map them, and they could
2949 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2951 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2952 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2953 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2964 * Merges and pads an image section's segments until they all are page-aligned
2965 * and have a size that is a multiple of the page size
2970 MmspPageAlignSegments
2972 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2978 BOOLEAN Initialized
;
2979 PMM_SECTION_SEGMENT EffectiveSegment
;
2981 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2983 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2987 Initialized
= FALSE
;
2989 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2991 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2994 * The first segment requires special handling
2998 ULONG_PTR VirtualAddress
;
2999 ULONG_PTR VirtualOffset
;
3001 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3003 /* Round down the virtual address to the nearest page */
3004 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3006 /* Round up the virtual size to the nearest page */
3007 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3008 EffectiveSegment
->VirtualAddress
;
3010 /* Adjust the raw address and size */
3011 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3013 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3019 * Garbage in, garbage out: unaligned base addresses make the file
3020 * offset point in curious and odd places, but that's what we were
3023 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3024 EffectiveSegment
->RawLength
+= VirtualOffset
;
3028 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3029 ULONG_PTR EndOfEffectiveSegment
;
3031 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3032 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3035 * The current segment begins exactly where the current effective
3036 * segment ended, therefore beginning a new effective segment
3038 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3041 ASSERT(LastSegment
<= i
);
3042 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3044 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3046 if (LastSegment
!= i
)
3049 * Copy the current segment. If necessary, the effective segment
3050 * will be expanded later
3052 *EffectiveSegment
= *Segment
;
3056 * Page-align the virtual size. We know for sure the virtual address
3059 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3060 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3063 * The current segment is still part of the current effective segment:
3064 * extend the effective segment to reflect this
3066 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3068 static const ULONG FlagsToProtection
[16] =
3076 PAGE_EXECUTE_READWRITE
,
3077 PAGE_EXECUTE_READWRITE
,
3082 PAGE_EXECUTE_WRITECOPY
,
3083 PAGE_EXECUTE_WRITECOPY
,
3084 PAGE_EXECUTE_WRITECOPY
,
3085 PAGE_EXECUTE_WRITECOPY
3088 unsigned ProtectionFlags
;
3091 * Extend the file size
3094 /* Unaligned segments must be contiguous within the file */
3095 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3096 EffectiveSegment
->RawLength
))
3101 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3104 * Extend the virtual size
3106 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3108 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3109 EffectiveSegment
->VirtualAddress
;
3112 * Merge the protection
3114 EffectiveSegment
->Protection
|= Segment
->Protection
;
3116 /* Clean up redundance */
3117 ProtectionFlags
= 0;
3119 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3120 ProtectionFlags
|= 1 << 0;
3122 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3123 ProtectionFlags
|= 1 << 1;
3125 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3126 ProtectionFlags
|= 1 << 2;
3128 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3129 ProtectionFlags
|= 1 << 3;
3131 ASSERT(ProtectionFlags
< 16);
3132 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3134 /* If a segment was required to be shared and cannot, fail */
3135 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3136 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3142 * We assume no holes between segments at this point
3146 KeBugCheck(MEMORY_MANAGEMENT
);
3150 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3156 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3157 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3159 LARGE_INTEGER Offset
;
3161 PVOID FileHeaderBuffer
;
3162 ULONG FileHeaderSize
;
3164 ULONG OldNrSegments
;
3169 * Read the beginning of the file (2 pages). Should be enough to contain
3170 * all (or most) of the headers
3172 Offset
.QuadPart
= 0;
3174 /* FIXME: use FileObject instead of FileHandle */
3175 Status
= ExeFmtpReadFile (FileHandle
,
3182 if (!NT_SUCCESS(Status
))
3185 if (FileHeaderSize
== 0)
3187 ExFreePool(FileHeaderBuffer
);
3188 return STATUS_UNSUCCESSFUL
;
3192 * Look for a loader that can handle this executable
3194 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3196 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3199 /* FIXME: use FileObject instead of FileHandle */
3200 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3206 ExeFmtpAllocateSegments
);
3208 if (!NT_SUCCESS(Status
))
3210 if (ImageSectionObject
->Segments
)
3212 ExFreePool(ImageSectionObject
->Segments
);
3213 ImageSectionObject
->Segments
= NULL
;
3217 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3221 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3224 * No loader handled the format
3226 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3228 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3229 ASSERT(!NT_SUCCESS(Status
));
3232 if (!NT_SUCCESS(Status
))
3235 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3240 /* FIXME? are these values platform-dependent? */
3241 if(ImageSectionObject
->StackReserve
== 0)
3242 ImageSectionObject
->StackReserve
= 0x40000;
3244 if(ImageSectionObject
->StackCommit
== 0)
3245 ImageSectionObject
->StackCommit
= 0x1000;
3247 if(ImageSectionObject
->ImageBase
== 0)
3249 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3250 ImageSectionObject
->ImageBase
= 0x10000000;
3252 ImageSectionObject
->ImageBase
= 0x00400000;
3256 * And now the fun part: fixing the segments
3259 /* Sort them by virtual address */
3260 MmspSortSegments(ImageSectionObject
, Flags
);
3262 /* Ensure they don't overlap in memory */
3263 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3264 return STATUS_INVALID_IMAGE_FORMAT
;
3266 /* Ensure they are aligned */
3267 OldNrSegments
= ImageSectionObject
->NrSegments
;
3269 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3270 return STATUS_INVALID_IMAGE_FORMAT
;
3272 /* Trim them if the alignment phase merged some of them */
3273 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3275 PMM_SECTION_SEGMENT Segments
;
3276 SIZE_T SizeOfSegments
;
3278 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3280 Segments
= ExAllocatePoolWithTag(PagedPool
,
3282 TAG_MM_SECTION_SEGMENT
);
3284 if (Segments
== NULL
)
3285 return STATUS_INSUFFICIENT_RESOURCES
;
3287 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3288 ExFreePool(ImageSectionObject
->Segments
);
3289 ImageSectionObject
->Segments
= Segments
;
3292 /* And finish their initialization */
3293 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3295 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3296 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3298 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3299 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3302 ASSERT(NT_SUCCESS(Status
));
3307 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3308 ACCESS_MASK DesiredAccess
,
3309 POBJECT_ATTRIBUTES ObjectAttributes
,
3310 PLARGE_INTEGER UMaximumSize
,
3311 ULONG SectionPageProtection
,
3312 ULONG AllocationAttributes
,
3315 PROS_SECTION_OBJECT Section
;
3317 PFILE_OBJECT FileObject
;
3318 PMM_SECTION_SEGMENT SectionSegments
;
3319 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3321 ULONG FileAccess
= 0;
3324 * Specifying a maximum size is meaningless for an image section
3326 if (UMaximumSize
!= NULL
)
3328 return(STATUS_INVALID_PARAMETER_4
);
3332 * Check file access required
3334 if (SectionPageProtection
& PAGE_READWRITE
||
3335 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3337 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3341 FileAccess
= FILE_READ_DATA
;
3345 * Reference the file handle
3347 Status
= ObReferenceObjectByHandle(FileHandle
,
3350 ExGetPreviousMode(),
3351 (PVOID
*)(PVOID
)&FileObject
,
3354 if (!NT_SUCCESS(Status
))
3360 * Create the section
3362 Status
= ObCreateObject (ExGetPreviousMode(),
3363 MmSectionObjectType
,
3365 ExGetPreviousMode(),
3367 sizeof(ROS_SECTION_OBJECT
),
3370 (PVOID
*)(PVOID
)&Section
);
3371 if (!NT_SUCCESS(Status
))
3373 ObDereferenceObject(FileObject
);
3382 Section
->MaximumSize
.QuadPart
= 0;
3383 Section
->SectionPageProtection
= SectionPageProtection
;
3384 Section
->AllocationAttributes
= AllocationAttributes
;
3387 * Initialized caching for this file object if previously caching
3388 * was initialized for the same on disk file
3390 Status
= CcTryToInitializeFileCache(FileObject
);
3392 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3394 NTSTATUS StatusExeFmt
;
3396 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3397 if (ImageSectionObject
== NULL
)
3399 ObDereferenceObject(FileObject
);
3400 ObDereferenceObject(Section
);
3401 return(STATUS_NO_MEMORY
);
3404 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3406 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3408 if (!NT_SUCCESS(StatusExeFmt
))
3410 if(ImageSectionObject
->Segments
!= NULL
)
3411 ExFreePool(ImageSectionObject
->Segments
);
3413 ExFreePool(ImageSectionObject
);
3414 ObDereferenceObject(Section
);
3415 ObDereferenceObject(FileObject
);
3416 return(StatusExeFmt
);
3419 Section
->ImageSection
= ImageSectionObject
;
3420 ASSERT(ImageSectionObject
->Segments
);
3425 Status
= MmspWaitForFileLock(FileObject
);
3426 if (!NT_SUCCESS(Status
))
3428 ExFreePool(ImageSectionObject
->Segments
);
3429 ExFreePool(ImageSectionObject
);
3430 ObDereferenceObject(Section
);
3431 ObDereferenceObject(FileObject
);
3435 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3436 ImageSectionObject
, NULL
))
3439 * An other thread has initialized the same image in the background
3441 ExFreePool(ImageSectionObject
->Segments
);
3442 ExFreePool(ImageSectionObject
);
3443 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3444 Section
->ImageSection
= ImageSectionObject
;
3445 SectionSegments
= ImageSectionObject
->Segments
;
3447 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3449 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3453 Status
= StatusExeFmt
;
3460 Status
= MmspWaitForFileLock(FileObject
);
3461 if (Status
!= STATUS_SUCCESS
)
3463 ObDereferenceObject(Section
);
3464 ObDereferenceObject(FileObject
);
3468 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3469 Section
->ImageSection
= ImageSectionObject
;
3470 SectionSegments
= ImageSectionObject
->Segments
;
3473 * Otherwise just reference all the section segments
3475 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3477 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3480 Status
= STATUS_SUCCESS
;
3482 Section
->FileObject
= FileObject
;
3483 CcRosReferenceCache(FileObject
);
3484 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3485 *SectionObject
= Section
;
3493 NtCreateSection (OUT PHANDLE SectionHandle
,
3494 IN ACCESS_MASK DesiredAccess
,
3495 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3496 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3497 IN ULONG SectionPageProtection OPTIONAL
,
3498 IN ULONG AllocationAttributes
,
3499 IN HANDLE FileHandle OPTIONAL
)
3501 LARGE_INTEGER SafeMaximumSize
;
3502 PVOID SectionObject
;
3503 KPROCESSOR_MODE PreviousMode
;
3504 NTSTATUS Status
= STATUS_SUCCESS
;
3506 PreviousMode
= ExGetPreviousMode();
3508 if(PreviousMode
!= KernelMode
)
3512 if (MaximumSize
!= NULL
)
3514 /* make a copy on the stack */
3515 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3516 MaximumSize
= &SafeMaximumSize
;
3518 ProbeForWriteHandle(SectionHandle
);
3520 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3522 Status
= _SEH2_GetExceptionCode();
3526 if(!NT_SUCCESS(Status
))
3532 Status
= MmCreateSection(&SectionObject
,
3536 SectionPageProtection
,
3537 AllocationAttributes
,
3540 if (NT_SUCCESS(Status
))
3542 Status
= ObInsertObject ((PVOID
)SectionObject
,
3554 /**********************************************************************
3572 NtOpenSection(PHANDLE SectionHandle
,
3573 ACCESS_MASK DesiredAccess
,
3574 POBJECT_ATTRIBUTES ObjectAttributes
)
3577 KPROCESSOR_MODE PreviousMode
;
3578 NTSTATUS Status
= STATUS_SUCCESS
;
3580 PreviousMode
= ExGetPreviousMode();
3582 if(PreviousMode
!= KernelMode
)
3586 ProbeForWriteHandle(SectionHandle
);
3588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3590 Status
= _SEH2_GetExceptionCode();
3594 if(!NT_SUCCESS(Status
))
3600 Status
= ObOpenObjectByName(ObjectAttributes
,
3601 MmSectionObjectType
,
3608 if(NT_SUCCESS(Status
))
3612 *SectionHandle
= hSection
;
3614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3616 Status
= _SEH2_GetExceptionCode();
3625 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3626 PROS_SECTION_OBJECT Section
,
3627 PMM_SECTION_SEGMENT Segment
,
3632 ULONG AllocationType
)
3636 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3638 BoundaryAddressMultiple
.QuadPart
= 0;
3640 Status
= MmCreateMemoryArea(AddressSpace
,
3641 MEMORY_AREA_SECTION_VIEW
,
3648 BoundaryAddressMultiple
);
3649 if (!NT_SUCCESS(Status
))
3651 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3652 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3656 ObReferenceObject((PVOID
)Section
);
3658 MArea
->Data
.SectionData
.Segment
= Segment
;
3659 MArea
->Data
.SectionData
.Section
= Section
;
3660 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3661 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3662 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3663 ViewSize
, 0, Protect
);
3665 return(STATUS_SUCCESS
);
3669 /**********************************************************************
3671 * NtMapViewOfSection
3674 * Maps a view of a section into the virtual address space of a
3679 * Handle of the section.
3682 * Handle of the process.
3685 * Desired base address (or NULL) on entry;
3686 * Actual base address of the view on exit.
3689 * Number of high order address bits that must be zero.
3692 * Size in bytes of the initially committed section of
3696 * Offset in bytes from the beginning of the section
3697 * to the beginning of the view.
3700 * Desired length of map (or zero to map all) on entry
3701 * Actual length mapped on exit.
3703 * InheritDisposition
3704 * Specified how the view is to be shared with
3708 * Type of allocation for the pages.
3711 * Protection for the committed region of the view.
3719 NtMapViewOfSection(IN HANDLE SectionHandle
,
3720 IN HANDLE ProcessHandle
,
3721 IN OUT PVOID
* BaseAddress OPTIONAL
,
3722 IN ULONG_PTR ZeroBits OPTIONAL
,
3723 IN SIZE_T CommitSize
,
3724 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3725 IN OUT PSIZE_T ViewSize
,
3726 IN SECTION_INHERIT InheritDisposition
,
3727 IN ULONG AllocationType OPTIONAL
,
3730 PVOID SafeBaseAddress
;
3731 LARGE_INTEGER SafeSectionOffset
;
3732 SIZE_T SafeViewSize
;
3733 PROS_SECTION_OBJECT Section
;
3735 KPROCESSOR_MODE PreviousMode
;
3736 PMMSUPPORT AddressSpace
;
3737 NTSTATUS Status
= STATUS_SUCCESS
;
3739 ACCESS_MASK DesiredAccess
;
3742 * Check the protection
3744 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3746 return STATUS_INVALID_PARAMETER_10
;
3749 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3750 if (tmpProtect
!= PAGE_NOACCESS
&&
3751 tmpProtect
!= PAGE_READONLY
&&
3752 tmpProtect
!= PAGE_READWRITE
&&
3753 tmpProtect
!= PAGE_WRITECOPY
&&
3754 tmpProtect
!= PAGE_EXECUTE
&&
3755 tmpProtect
!= PAGE_EXECUTE_READ
&&
3756 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3757 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3759 return STATUS_INVALID_PAGE_PROTECTION
;
3762 PreviousMode
= ExGetPreviousMode();
3764 if(PreviousMode
!= KernelMode
)
3766 SafeBaseAddress
= NULL
;
3767 SafeSectionOffset
.QuadPart
= 0;
3772 if(BaseAddress
!= NULL
)
3774 ProbeForWritePointer(BaseAddress
);
3775 SafeBaseAddress
= *BaseAddress
;
3777 if(SectionOffset
!= NULL
)
3779 ProbeForWriteLargeInteger(SectionOffset
);
3780 SafeSectionOffset
= *SectionOffset
;
3782 ProbeForWriteSize_t(ViewSize
);
3783 SafeViewSize
= *ViewSize
;
3785 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3787 Status
= _SEH2_GetExceptionCode();
3791 if(!NT_SUCCESS(Status
))
3798 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3799 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3800 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3803 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3805 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3806 PROCESS_VM_OPERATION
,
3809 (PVOID
*)(PVOID
)&Process
,
3811 if (!NT_SUCCESS(Status
))
3816 AddressSpace
= &Process
->Vm
;
3818 /* Convert NT Protection Attr to Access Mask */
3819 if (Protect
== PAGE_READONLY
)
3821 DesiredAccess
= SECTION_MAP_READ
;
3823 else if (Protect
== PAGE_READWRITE
)
3825 DesiredAccess
= SECTION_MAP_WRITE
;
3827 else if (Protect
== PAGE_WRITECOPY
)
3829 DesiredAccess
= SECTION_QUERY
;
3831 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3834 DesiredAccess
= SECTION_MAP_READ
;
3837 Status
= ObReferenceObjectByHandle(SectionHandle
,
3839 MmSectionObjectType
,
3841 (PVOID
*)(PVOID
)&Section
,
3843 if (!(NT_SUCCESS(Status
)))
3845 DPRINT("ObReference failed rc=%x\n",Status
);
3846 ObDereferenceObject(Process
);
3850 Status
= MmMapViewOfSection(Section
,
3852 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3855 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3856 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3861 /* Check if this is an image for the current process */
3862 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3863 (Process
== PsGetCurrentProcess()) &&
3864 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3866 /* Notify the debugger */
3867 DbgkMapViewOfSection(Section
,
3869 SafeSectionOffset
.LowPart
,
3873 ObDereferenceObject(Section
);
3874 ObDereferenceObject(Process
);
3876 if(NT_SUCCESS(Status
))
3878 /* copy parameters back to the caller */
3881 if(BaseAddress
!= NULL
)
3883 *BaseAddress
= SafeBaseAddress
;
3885 if(SectionOffset
!= NULL
)
3887 *SectionOffset
= SafeSectionOffset
;
3889 if(ViewSize
!= NULL
)
3891 *ViewSize
= SafeViewSize
;
3894 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3896 Status
= _SEH2_GetExceptionCode();
3905 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3906 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3909 PFILE_OBJECT FileObject
;
3912 SWAPENTRY SavedSwapEntry
;
3915 PROS_SECTION_OBJECT Section
;
3916 PMM_SECTION_SEGMENT Segment
;
3917 PMMSUPPORT AddressSpace
;
3920 AddressSpace
= (PMMSUPPORT
)Context
;
3921 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3923 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3925 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3926 MemoryArea
->Data
.SectionData
.ViewOffset
;
3928 Section
= MemoryArea
->Data
.SectionData
.Section
;
3929 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3931 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3935 MmUnlockSectionSegment(Segment
);
3936 MmUnlockAddressSpace(AddressSpace
);
3938 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3939 if (Status
!= STATUS_SUCCESS
)
3941 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3942 KeBugCheck(MEMORY_MANAGEMENT
);
3945 MmLockAddressSpace(AddressSpace
);
3946 MmLockSectionSegment(Segment
);
3947 MmspCompleteAndReleasePageOp(PageOp
);
3948 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3951 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3954 * For a dirty, datafile, non-private page mark it as dirty in the
3957 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3959 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3961 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3962 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3963 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3964 ASSERT(SwapEntry
== 0);
3973 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3975 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3976 KeBugCheck(MEMORY_MANAGEMENT
);
3978 MmFreeSwapPage(SwapEntry
);
3982 if (IS_SWAP_FROM_SSE(Entry
) ||
3983 Page
!= PFN_FROM_SSE(Entry
))
3988 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3990 DPRINT1("Found a private page in a pagefile section.\n");
3991 KeBugCheck(MEMORY_MANAGEMENT
);
3994 * Just dereference private pages
3996 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3997 if (SavedSwapEntry
!= 0)
3999 MmFreeSwapPage(SavedSwapEntry
);
4000 MmSetSavedSwapEntryPage(Page
, 0);
4002 MmDeleteRmap(Page
, Process
, Address
);
4003 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4007 MmDeleteRmap(Page
, Process
, Address
);
4008 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4014 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4018 PMEMORY_AREA MemoryArea
;
4019 PROS_SECTION_OBJECT Section
;
4020 PMM_SECTION_SEGMENT Segment
;
4021 PLIST_ENTRY CurrentEntry
;
4022 PMM_REGION CurrentRegion
;
4023 PLIST_ENTRY RegionListHead
;
4025 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4027 if (MemoryArea
== NULL
)
4029 return(STATUS_UNSUCCESSFUL
);
4032 MemoryArea
->DeleteInProgress
= TRUE
;
4033 Section
= MemoryArea
->Data
.SectionData
.Section
;
4034 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4036 MmLockSectionSegment(Segment
);
4038 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4039 while (!IsListEmpty(RegionListHead
))
4041 CurrentEntry
= RemoveHeadList(RegionListHead
);
4042 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4043 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4046 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4048 Status
= MmFreeMemoryArea(AddressSpace
,
4055 Status
= MmFreeMemoryArea(AddressSpace
,
4060 MmUnlockSectionSegment(Segment
);
4061 ObDereferenceObject(Section
);
4062 return(STATUS_SUCCESS
);
4069 MmUnmapViewOfSection(PEPROCESS Process
,
4073 PMEMORY_AREA MemoryArea
;
4074 PMMSUPPORT AddressSpace
;
4075 PROS_SECTION_OBJECT Section
;
4078 PVOID ImageBaseAddress
= 0;
4080 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4081 Process
, BaseAddress
);
4085 AddressSpace
= &Process
->Vm
;
4087 MmLockAddressSpace(AddressSpace
);
4088 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4090 if (MemoryArea
== NULL
||
4091 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4092 MemoryArea
->DeleteInProgress
)
4094 MmUnlockAddressSpace(AddressSpace
);
4095 return STATUS_NOT_MAPPED_VIEW
;
4098 MemoryArea
->DeleteInProgress
= TRUE
;
4100 while (MemoryArea
->PageOpCount
)
4102 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4106 Offset
-= PAGE_SIZE
;
4107 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4108 MemoryArea
->Data
.SectionData
.Segment
,
4109 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4112 MmUnlockAddressSpace(AddressSpace
);
4113 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4114 if (Status
!= STATUS_SUCCESS
)
4116 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4117 KeBugCheck(MEMORY_MANAGEMENT
);
4119 MmLockAddressSpace(AddressSpace
);
4120 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4122 if (MemoryArea
== NULL
||
4123 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4125 MmUnlockAddressSpace(AddressSpace
);
4126 return STATUS_NOT_MAPPED_VIEW
;
4133 Section
= MemoryArea
->Data
.SectionData
.Section
;
4135 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4139 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4140 PMM_SECTION_SEGMENT SectionSegments
;
4141 PMM_SECTION_SEGMENT Segment
;
4143 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4144 ImageSectionObject
= Section
->ImageSection
;
4145 SectionSegments
= ImageSectionObject
->Segments
;
4146 NrSegments
= ImageSectionObject
->NrSegments
;
4148 /* Search for the current segment within the section segments
4149 * and calculate the image base address */
4150 for (i
= 0; i
< NrSegments
; i
++)
4152 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4154 if (Segment
== &SectionSegments
[i
])
4156 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4161 if (i
>= NrSegments
)
4163 KeBugCheck(MEMORY_MANAGEMENT
);
4166 for (i
= 0; i
< NrSegments
; i
++)
4168 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4170 PVOID SBaseAddress
= (PVOID
)
4171 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4173 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4179 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4182 MmUnlockAddressSpace(AddressSpace
);
4184 /* Notify debugger */
4185 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4187 return(STATUS_SUCCESS
);
4190 /**********************************************************************
4192 * NtUnmapViewOfSection
4207 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4211 KPROCESSOR_MODE PreviousMode
;
4214 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4215 ProcessHandle
, BaseAddress
);
4217 PreviousMode
= ExGetPreviousMode();
4219 DPRINT("Referencing process\n");
4220 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4221 PROCESS_VM_OPERATION
,
4224 (PVOID
*)(PVOID
)&Process
,
4226 if (!NT_SUCCESS(Status
))
4228 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4232 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4234 ObDereferenceObject(Process
);
4241 * Queries the information of a section object.
4243 * @param SectionHandle
4244 * Handle to the section object. It must be opened with SECTION_QUERY
4246 * @param SectionInformationClass
4247 * Index to a certain information structure. Can be either
4248 * SectionBasicInformation or SectionImageInformation. The latter
4249 * is valid only for sections that were created with the SEC_IMAGE
4251 * @param SectionInformation
4252 * Caller supplies storage for resulting information.
4254 * Size of the supplied storage.
4255 * @param ResultLength
4263 NtQuerySection(IN HANDLE SectionHandle
,
4264 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4265 OUT PVOID SectionInformation
,
4266 IN ULONG SectionInformationLength
,
4267 OUT PULONG ResultLength OPTIONAL
)
4269 PROS_SECTION_OBJECT Section
;
4270 KPROCESSOR_MODE PreviousMode
;
4271 NTSTATUS Status
= STATUS_SUCCESS
;
4274 PreviousMode
= ExGetPreviousMode();
4276 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4278 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4280 SectionInformationLength
,
4284 if(!NT_SUCCESS(Status
))
4286 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4290 Status
= ObReferenceObjectByHandle(SectionHandle
,
4292 MmSectionObjectType
,
4294 (PVOID
*)(PVOID
)&Section
,
4296 if (NT_SUCCESS(Status
))
4298 switch (SectionInformationClass
)
4300 case SectionBasicInformation
:
4302 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4306 Sbi
->Attributes
= Section
->AllocationAttributes
;
4307 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4309 Sbi
->BaseAddress
= 0;
4310 Sbi
->Size
.QuadPart
= 0;
4314 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4315 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4318 if (ResultLength
!= NULL
)
4320 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4322 Status
= STATUS_SUCCESS
;
4324 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4326 Status
= _SEH2_GetExceptionCode();
4333 case SectionImageInformation
:
4335 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4339 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4340 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4342 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4343 ImageSectionObject
= Section
->ImageSection
;
4345 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4346 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4347 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4348 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4349 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4350 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4351 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4352 Sii
->Machine
= ImageSectionObject
->Machine
;
4353 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4356 if (ResultLength
!= NULL
)
4358 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4360 Status
= STATUS_SUCCESS
;
4362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4364 Status
= _SEH2_GetExceptionCode();
4372 ObDereferenceObject(Section
);
4380 * Extends size of file backed section.
4382 * @param SectionHandle
4383 * Handle to the section object. It must be opened with
4384 * SECTION_EXTEND_SIZE access.
4385 * @param NewMaximumSize
4386 * New maximum size of the section in bytes.
4390 * @todo Move the actual code to internal function MmExtendSection.
4394 NtExtendSection(IN HANDLE SectionHandle
,
4395 IN PLARGE_INTEGER NewMaximumSize
)
4397 LARGE_INTEGER SafeNewMaximumSize
;
4398 PROS_SECTION_OBJECT Section
;
4399 KPROCESSOR_MODE PreviousMode
;
4400 NTSTATUS Status
= STATUS_SUCCESS
;
4402 PreviousMode
= ExGetPreviousMode();
4404 if(PreviousMode
!= KernelMode
)
4408 /* make a copy on the stack */
4409 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4410 NewMaximumSize
= &SafeNewMaximumSize
;
4412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4414 Status
= _SEH2_GetExceptionCode();
4418 if(!NT_SUCCESS(Status
))
4424 Status
= ObReferenceObjectByHandle(SectionHandle
,
4425 SECTION_EXTEND_SIZE
,
4426 MmSectionObjectType
,
4430 if (!NT_SUCCESS(Status
))
4435 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4437 ObfDereferenceObject(Section
);
4438 return STATUS_INVALID_PARAMETER
;
4442 * - Acquire file extneding resource.
4443 * - Check if we're not resizing the section below it's actual size!
4444 * - Extend segments if needed.
4445 * - Set file information (FileAllocationInformation) to the new size.
4446 * - Release file extending resource.
4449 ObDereferenceObject(Section
);
4451 return STATUS_NOT_IMPLEMENTED
;
4455 /**********************************************************************
4457 * MmAllocateSection@4
4467 * Code taken from ntoskrnl/mm/special.c.
4472 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4477 PMMSUPPORT AddressSpace
;
4478 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4480 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4482 BoundaryAddressMultiple
.QuadPart
= 0;
4484 AddressSpace
= MmGetKernelAddressSpace();
4485 Result
= BaseAddress
;
4486 MmLockAddressSpace(AddressSpace
);
4487 Status
= MmCreateMemoryArea (AddressSpace
,
4495 BoundaryAddressMultiple
);
4496 MmUnlockAddressSpace(AddressSpace
);
4498 if (!NT_SUCCESS(Status
))
4502 DPRINT("Result %p\n",Result
);
4504 /* Create a virtual mapping for this memory area */
4505 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4507 return ((PVOID
)Result
);
4511 /**********************************************************************
4513 * MmMapViewOfSection
4516 * Maps a view of a section into the virtual address space of a
4521 * Pointer to the section object.
4524 * Pointer to the process.
4527 * Desired base address (or NULL) on entry;
4528 * Actual base address of the view on exit.
4531 * Number of high order address bits that must be zero.
4534 * Size in bytes of the initially committed section of
4538 * Offset in bytes from the beginning of the section
4539 * to the beginning of the view.
4542 * Desired length of map (or zero to map all) on entry
4543 * Actual length mapped on exit.
4545 * InheritDisposition
4546 * Specified how the view is to be shared with
4550 * Type of allocation for the pages.
4553 * Protection for the committed region of the view.
4561 MmMapViewOfSection(IN PVOID SectionObject
,
4562 IN PEPROCESS Process
,
4563 IN OUT PVOID
*BaseAddress
,
4564 IN ULONG_PTR ZeroBits
,
4565 IN SIZE_T CommitSize
,
4566 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4567 IN OUT PSIZE_T ViewSize
,
4568 IN SECTION_INHERIT InheritDisposition
,
4569 IN ULONG AllocationType
,
4572 PROS_SECTION_OBJECT Section
;
4573 PMMSUPPORT AddressSpace
;
4575 NTSTATUS Status
= STATUS_SUCCESS
;
4579 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4581 return STATUS_INVALID_PAGE_PROTECTION
;
4585 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4586 AddressSpace
= &Process
->Vm
;
4588 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4590 MmLockAddressSpace(AddressSpace
);
4592 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4596 ULONG_PTR ImageBase
;
4598 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4599 PMM_SECTION_SEGMENT SectionSegments
;
4601 ImageSectionObject
= Section
->ImageSection
;
4602 SectionSegments
= ImageSectionObject
->Segments
;
4603 NrSegments
= ImageSectionObject
->NrSegments
;
4606 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4609 ImageBase
= ImageSectionObject
->ImageBase
;
4613 for (i
= 0; i
< NrSegments
; i
++)
4615 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4617 ULONG_PTR MaxExtent
;
4618 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4619 SectionSegments
[i
].Length
;
4620 ImageSize
= max(ImageSize
, MaxExtent
);
4624 ImageSectionObject
->ImageSize
= ImageSize
;
4626 /* Check there is enough space to map the section at that point. */
4627 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4628 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4630 /* Fail if the user requested a fixed base address. */
4631 if ((*BaseAddress
) != NULL
)
4633 MmUnlockAddressSpace(AddressSpace
);
4634 return(STATUS_UNSUCCESSFUL
);
4636 /* Otherwise find a gap to map the image. */
4637 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4640 MmUnlockAddressSpace(AddressSpace
);
4641 return(STATUS_UNSUCCESSFUL
);
4645 for (i
= 0; i
< NrSegments
; i
++)
4647 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4649 PVOID SBaseAddress
= (PVOID
)
4650 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4651 MmLockSectionSegment(&SectionSegments
[i
]);
4652 Status
= MmMapViewOfSegment(AddressSpace
,
4654 &SectionSegments
[i
],
4656 SectionSegments
[i
].Length
,
4657 SectionSegments
[i
].Protection
,
4660 MmUnlockSectionSegment(&SectionSegments
[i
]);
4661 if (!NT_SUCCESS(Status
))
4663 MmUnlockAddressSpace(AddressSpace
);
4669 *BaseAddress
= (PVOID
)ImageBase
;
4673 /* check for write access */
4674 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4675 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4677 MmUnlockAddressSpace(AddressSpace
);
4678 return STATUS_SECTION_PROTECTION
;
4680 /* check for read access */
4681 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4682 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4684 MmUnlockAddressSpace(AddressSpace
);
4685 return STATUS_SECTION_PROTECTION
;
4687 /* check for execute access */
4688 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4689 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4691 MmUnlockAddressSpace(AddressSpace
);
4692 return STATUS_SECTION_PROTECTION
;
4695 if (ViewSize
== NULL
)
4697 /* Following this pointer would lead to us to the dark side */
4698 /* What to do? Bugcheck? Return status? Do the mambo? */
4699 KeBugCheck(MEMORY_MANAGEMENT
);
4702 if (SectionOffset
== NULL
)
4708 ViewOffset
= SectionOffset
->u
.LowPart
;
4711 if ((ViewOffset
% PAGE_SIZE
) != 0)
4713 MmUnlockAddressSpace(AddressSpace
);
4714 return(STATUS_MAPPED_ALIGNMENT
);
4717 if ((*ViewSize
) == 0)
4719 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4721 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4723 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4726 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4728 MmLockSectionSegment(Section
->Segment
);
4729 Status
= MmMapViewOfSegment(AddressSpace
,
4736 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4737 MmUnlockSectionSegment(Section
->Segment
);
4738 if (!NT_SUCCESS(Status
))
4740 MmUnlockAddressSpace(AddressSpace
);
4745 MmUnlockAddressSpace(AddressSpace
);
4747 return(STATUS_SUCCESS
);
4754 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4755 IN PLARGE_INTEGER NewFileSize
)
4757 /* Check whether an ImageSectionObject exists */
4758 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4760 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4764 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4766 PMM_SECTION_SEGMENT Segment
;
4768 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4771 if (Segment
->ReferenceCount
!= 0)
4773 /* Check size of file */
4774 if (SectionObjectPointer
->SharedCacheMap
)
4776 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4777 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4785 /* Something must gone wrong
4786 * how can we have a Section but no
4788 DPRINT1("ERROR: DataSectionObject without reference!\n");
4792 DPRINT("FIXME: didn't check for outstanding write probes\n");
4802 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4812 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4813 IN MMFLUSH_TYPE FlushType
)
4817 case MmFlushForDelete
:
4818 if (SectionObjectPointer
->ImageSectionObject
||
4819 SectionObjectPointer
->DataSectionObject
)
4823 CcRosSetRemoveOnClose(SectionObjectPointer
);
4825 case MmFlushForWrite
:
4835 MmForceSectionClosed (
4836 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4837 IN BOOLEAN DelayClose
)
4848 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4849 OUT PVOID
* MappedBase
,
4850 IN OUT PULONG ViewSize
)
4852 PROS_SECTION_OBJECT Section
;
4853 PMMSUPPORT AddressSpace
;
4856 DPRINT("MmMapViewInSystemSpace() called\n");
4858 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4859 AddressSpace
= MmGetKernelAddressSpace();
4861 MmLockAddressSpace(AddressSpace
);
4864 if ((*ViewSize
) == 0)
4866 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4868 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4870 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4873 MmLockSectionSegment(Section
->Segment
);
4876 Status
= MmMapViewOfSegment(AddressSpace
,
4885 MmUnlockSectionSegment(Section
->Segment
);
4886 MmUnlockAddressSpace(AddressSpace
);
4896 MmMapViewInSessionSpace (
4898 OUT PVOID
*MappedBase
,
4899 IN OUT PSIZE_T ViewSize
4903 return STATUS_NOT_IMPLEMENTED
;
4911 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4913 PMMSUPPORT AddressSpace
;
4916 DPRINT("MmUnmapViewInSystemSpace() called\n");
4918 AddressSpace
= MmGetKernelAddressSpace();
4920 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4930 MmUnmapViewInSessionSpace (
4935 return STATUS_NOT_IMPLEMENTED
;
4942 MmSetBankedSection (ULONG Unknown0
,
4950 return (STATUS_NOT_IMPLEMENTED
);
4954 /**********************************************************************
4959 * Creates a section object.
4962 * SectionObject (OUT)
4963 * Caller supplied storage for the resulting pointer
4964 * to a SECTION_OBJECT instance;
4967 * Specifies the desired access to the section can be a
4969 * STANDARD_RIGHTS_REQUIRED |
4971 * SECTION_MAP_WRITE |
4972 * SECTION_MAP_READ |
4973 * SECTION_MAP_EXECUTE
4975 * ObjectAttributes [OPTIONAL]
4976 * Initialized attributes for the object can be used
4977 * to create a named section;
4980 * Maximizes the size of the memory section. Must be
4981 * non-NULL for a page-file backed section.
4982 * If value specified for a mapped file and the file is
4983 * not large enough, file will be extended.
4985 * SectionPageProtection
4986 * Can be a combination of:
4992 * AllocationAttributes
4993 * Can be a combination of:
4998 * Handle to a file to create a section mapped to a file
4999 * instead of a memory backed section;
5010 MmCreateSection (OUT PVOID
* Section
,
5011 IN ACCESS_MASK DesiredAccess
,
5012 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5013 IN PLARGE_INTEGER MaximumSize
,
5014 IN ULONG SectionPageProtection
,
5015 IN ULONG AllocationAttributes
,
5016 IN HANDLE FileHandle OPTIONAL
,
5017 IN PFILE_OBJECT File OPTIONAL
)
5020 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5023 * Check the protection
5025 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5026 if (Protection
!= PAGE_READONLY
&&
5027 Protection
!= PAGE_READWRITE
&&
5028 Protection
!= PAGE_WRITECOPY
&&
5029 Protection
!= PAGE_EXECUTE
&&
5030 Protection
!= PAGE_EXECUTE_READ
&&
5031 Protection
!= PAGE_EXECUTE_READWRITE
&&
5032 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5034 return STATUS_INVALID_PAGE_PROTECTION
;
5037 if (AllocationAttributes
& SEC_IMAGE
)
5039 return(MmCreateImageSection(SectionObject
,
5043 SectionPageProtection
,
5044 AllocationAttributes
,
5048 if (FileHandle
!= NULL
)
5050 return(MmCreateDataFileSection(SectionObject
,
5054 SectionPageProtection
,
5055 AllocationAttributes
,
5059 return(MmCreatePageFileSection(SectionObject
,
5063 SectionPageProtection
,
5064 AllocationAttributes
));
5069 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5070 IN OUT PULONG_PTR NumberOfPages
,
5071 IN OUT PULONG_PTR UserPfnArray
)
5074 return STATUS_NOT_IMPLEMENTED
;
5079 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5080 IN ULONG_PTR NumberOfPages
,
5081 IN OUT PULONG_PTR UserPfnArray
)
5084 return STATUS_NOT_IMPLEMENTED
;
5089 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5090 IN ULONG_PTR NumberOfPages
,
5091 IN OUT PULONG_PTR UserPfnArray
)
5094 return STATUS_NOT_IMPLEMENTED
;
5099 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5100 IN OUT PULONG_PTR NumberOfPages
,
5101 IN OUT PULONG_PTR UserPfnArray
)
5104 return STATUS_NOT_IMPLEMENTED
;
5109 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5110 IN PVOID File2MappedAsFile
)
5113 return STATUS_NOT_IMPLEMENTED
;