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
,
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
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
, ' mM');
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 MmCreatePhysicalMemorySection();
2334 return(STATUS_SUCCESS
);
2339 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2340 ACCESS_MASK DesiredAccess
,
2341 POBJECT_ATTRIBUTES ObjectAttributes
,
2342 PLARGE_INTEGER UMaximumSize
,
2343 ULONG SectionPageProtection
,
2344 ULONG AllocationAttributes
)
2346 * Create a section which is backed by the pagefile
2349 LARGE_INTEGER MaximumSize
;
2350 PROS_SECTION_OBJECT Section
;
2351 PMM_SECTION_SEGMENT Segment
;
2354 if (UMaximumSize
== NULL
)
2356 return(STATUS_UNSUCCESSFUL
);
2358 MaximumSize
= *UMaximumSize
;
2361 * Create the section
2363 Status
= ObCreateObject(ExGetPreviousMode(),
2364 MmSectionObjectType
,
2366 ExGetPreviousMode(),
2368 sizeof(ROS_SECTION_OBJECT
),
2371 (PVOID
*)(PVOID
)&Section
);
2372 if (!NT_SUCCESS(Status
))
2380 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2381 Section
->SectionPageProtection
= SectionPageProtection
;
2382 Section
->AllocationAttributes
= AllocationAttributes
;
2383 Section
->MaximumSize
= MaximumSize
;
2384 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2385 TAG_MM_SECTION_SEGMENT
);
2386 if (Segment
== NULL
)
2388 ObDereferenceObject(Section
);
2389 return(STATUS_NO_MEMORY
);
2391 Section
->Segment
= Segment
;
2392 Segment
->ReferenceCount
= 1;
2393 ExInitializeFastMutex(&Segment
->Lock
);
2394 Segment
->FileOffset
= 0;
2395 Segment
->Protection
= SectionPageProtection
;
2396 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2397 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2398 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2399 Segment
->WriteCopy
= FALSE
;
2400 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2401 Segment
->VirtualAddress
= 0;
2402 Segment
->Characteristics
= 0;
2403 *SectionObject
= Section
;
2404 return(STATUS_SUCCESS
);
2410 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2411 ACCESS_MASK DesiredAccess
,
2412 POBJECT_ATTRIBUTES ObjectAttributes
,
2413 PLARGE_INTEGER UMaximumSize
,
2414 ULONG SectionPageProtection
,
2415 ULONG AllocationAttributes
,
2418 * Create a section backed by a data file
2421 PROS_SECTION_OBJECT Section
;
2423 LARGE_INTEGER MaximumSize
;
2424 PFILE_OBJECT FileObject
;
2425 PMM_SECTION_SEGMENT Segment
;
2427 IO_STATUS_BLOCK Iosb
;
2428 LARGE_INTEGER Offset
;
2430 FILE_STANDARD_INFORMATION FileInfo
;
2433 * Create the section
2435 Status
= ObCreateObject(ExGetPreviousMode(),
2436 MmSectionObjectType
,
2438 ExGetPreviousMode(),
2440 sizeof(ROS_SECTION_OBJECT
),
2443 (PVOID
*)(PVOID
)&Section
);
2444 if (!NT_SUCCESS(Status
))
2451 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2452 Section
->SectionPageProtection
= SectionPageProtection
;
2453 Section
->AllocationAttributes
= AllocationAttributes
;
2456 * Check file access required
2458 if (SectionPageProtection
& PAGE_READWRITE
||
2459 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2461 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2465 FileAccess
= FILE_READ_DATA
;
2469 * Reference the file handle
2471 Status
= ObReferenceObjectByHandle(FileHandle
,
2474 ExGetPreviousMode(),
2475 (PVOID
*)(PVOID
)&FileObject
,
2477 if (!NT_SUCCESS(Status
))
2479 ObDereferenceObject(Section
);
2484 * FIXME: This is propably not entirely correct. We can't look into
2485 * the standard FCB header because it might not be initialized yet
2486 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2487 * standard file information is filled on first request).
2489 Status
= IoQueryFileInformation(FileObject
,
2490 FileStandardInformation
,
2491 sizeof(FILE_STANDARD_INFORMATION
),
2494 if (!NT_SUCCESS(Status
))
2496 ObDereferenceObject(Section
);
2497 ObDereferenceObject(FileObject
);
2502 * FIXME: Revise this once a locking order for file size changes is
2505 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2507 MaximumSize
= *UMaximumSize
;
2511 MaximumSize
= FileInfo
.EndOfFile
;
2512 /* Mapping zero-sized files isn't allowed. */
2513 if (MaximumSize
.QuadPart
== 0)
2515 ObDereferenceObject(Section
);
2516 ObDereferenceObject(FileObject
);
2517 return STATUS_FILE_INVALID
;
2521 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2523 Status
= IoSetInformation(FileObject
,
2524 FileAllocationInformation
,
2525 sizeof(LARGE_INTEGER
),
2527 if (!NT_SUCCESS(Status
))
2529 ObDereferenceObject(Section
);
2530 ObDereferenceObject(FileObject
);
2531 return(STATUS_SECTION_NOT_EXTENDED
);
2535 if (FileObject
->SectionObjectPointer
== NULL
||
2536 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2539 * Read a bit so caching is initiated for the file object.
2540 * This is only needed because MiReadPage currently cannot
2541 * handle non-cached streams.
2543 Offset
.QuadPart
= 0;
2544 Status
= ZwReadFile(FileHandle
,
2553 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2555 ObDereferenceObject(Section
);
2556 ObDereferenceObject(FileObject
);
2559 if (FileObject
->SectionObjectPointer
== NULL
||
2560 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2562 /* FIXME: handle this situation */
2563 ObDereferenceObject(Section
);
2564 ObDereferenceObject(FileObject
);
2565 return STATUS_INVALID_PARAMETER
;
2572 Status
= MmspWaitForFileLock(FileObject
);
2573 if (Status
!= STATUS_SUCCESS
)
2575 ObDereferenceObject(Section
);
2576 ObDereferenceObject(FileObject
);
2581 * If this file hasn't been mapped as a data file before then allocate a
2582 * section segment to describe the data file mapping
2584 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2586 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2587 TAG_MM_SECTION_SEGMENT
);
2588 if (Segment
== NULL
)
2590 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2591 ObDereferenceObject(Section
);
2592 ObDereferenceObject(FileObject
);
2593 return(STATUS_NO_MEMORY
);
2595 Section
->Segment
= Segment
;
2596 Segment
->ReferenceCount
= 1;
2597 ExInitializeFastMutex(&Segment
->Lock
);
2599 * Set the lock before assigning the segment to the file object
2601 ExAcquireFastMutex(&Segment
->Lock
);
2602 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2604 Segment
->FileOffset
= 0;
2605 Segment
->Protection
= SectionPageProtection
;
2606 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2607 Segment
->Characteristics
= 0;
2608 Segment
->WriteCopy
= FALSE
;
2609 if (AllocationAttributes
& SEC_RESERVE
)
2611 Segment
->Length
= Segment
->RawLength
= 0;
2615 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2616 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2618 Segment
->VirtualAddress
= 0;
2619 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2624 * If the file is already mapped as a data file then we may need
2628 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2630 Section
->Segment
= Segment
;
2631 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2632 MmLockSectionSegment(Segment
);
2634 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2635 !(AllocationAttributes
& SEC_RESERVE
))
2637 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2638 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2641 MmUnlockSectionSegment(Segment
);
2642 Section
->FileObject
= FileObject
;
2643 Section
->MaximumSize
= MaximumSize
;
2644 CcRosReferenceCache(FileObject
);
2645 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2646 *SectionObject
= Section
;
2647 return(STATUS_SUCCESS
);
2651 TODO: not that great (declaring loaders statically, having to declare all of
2652 them, having to keep them extern, etc.), will fix in the future
2654 extern NTSTATUS NTAPI PeFmtCreateSection
2656 IN CONST VOID
* FileHeader
,
2657 IN SIZE_T FileHeaderSize
,
2659 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2661 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2662 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2665 extern NTSTATUS NTAPI ElfFmtCreateSection
2667 IN CONST VOID
* FileHeader
,
2668 IN SIZE_T FileHeaderSize
,
2670 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2672 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2673 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2676 /* TODO: this is a standard DDK/PSDK macro */
2677 #ifndef RTL_NUMBER_OF
2678 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2681 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2692 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2694 SIZE_T SizeOfSegments
;
2695 PMM_SECTION_SEGMENT Segments
;
2697 /* TODO: check for integer overflow */
2698 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2700 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2702 TAG_MM_SECTION_SEGMENT
);
2705 RtlZeroMemory(Segments
, SizeOfSegments
);
2713 ExeFmtpReadFile(IN PVOID File
,
2714 IN PLARGE_INTEGER Offset
,
2717 OUT PVOID
* AllocBase
,
2718 OUT PULONG ReadSize
)
2721 LARGE_INTEGER FileOffset
;
2723 ULONG OffsetAdjustment
;
2728 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2732 KeBugCheck(MEMORY_MANAGEMENT
);
2735 FileOffset
= *Offset
;
2737 /* Negative/special offset: it cannot be used in this context */
2738 if(FileOffset
.u
.HighPart
< 0)
2740 KeBugCheck(MEMORY_MANAGEMENT
);
2743 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2744 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2745 FileOffset
.u
.LowPart
= AdjustOffset
;
2747 BufferSize
= Length
+ OffsetAdjustment
;
2748 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2751 * It's ok to use paged pool, because this is a temporary buffer only used in
2752 * the loading of executables. The assumption is that MmCreateSection is
2753 * always called at low IRQLs and that these buffers don't survive a brief
2754 * initialization phase
2756 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2763 Status
= MmspPageRead(File
,
2770 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2771 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2772 * to initialize internal state is even worse. Our cache manager is in need of
2776 IO_STATUS_BLOCK Iosb
;
2778 Status
= ZwReadFile(File
,
2788 if(NT_SUCCESS(Status
))
2790 UsedSize
= Iosb
.Information
;
2795 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2797 Status
= STATUS_IN_PAGE_ERROR
;
2798 ASSERT(!NT_SUCCESS(Status
));
2801 if(NT_SUCCESS(Status
))
2803 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2804 *AllocBase
= Buffer
;
2805 *ReadSize
= UsedSize
- OffsetAdjustment
;
2809 ExFreePoolWithTag(Buffer
, 'rXmM');
2816 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2817 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2818 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2823 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2827 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2829 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2830 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2837 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2841 MmspAssertSegmentsSorted(ImageSectionObject
);
2843 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2845 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2849 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2850 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2851 ImageSectionObject
->Segments
[i
- 1].Length
));
2859 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2863 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2865 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2866 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2874 MmspCompareSegments(const void * x
,
2877 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2878 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2881 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2882 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2886 * Ensures an image section's segments are sorted in memory
2891 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2894 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2896 MmspAssertSegmentsSorted(ImageSectionObject
);
2900 qsort(ImageSectionObject
->Segments
,
2901 ImageSectionObject
->NrSegments
,
2902 sizeof(ImageSectionObject
->Segments
[0]),
2903 MmspCompareSegments
);
2909 * Ensures an image section's segments don't overlap in memory and don't have
2910 * gaps and don't have a null size. We let them map to overlapping file regions,
2911 * though - that's not necessarily an error
2916 MmspCheckSegmentBounds
2918 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2924 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2926 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2930 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2932 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2934 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2942 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2943 * page could be OK (Windows seems to be OK with them), and larger gaps
2944 * could lead to image sections spanning several discontiguous regions
2945 * (NtMapViewOfSection could then refuse to map them, and they could
2946 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2948 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2949 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2950 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2961 * Merges and pads an image section's segments until they all are page-aligned
2962 * and have a size that is a multiple of the page size
2967 MmspPageAlignSegments
2969 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2975 BOOLEAN Initialized
;
2976 PMM_SECTION_SEGMENT EffectiveSegment
;
2978 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2980 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2984 Initialized
= FALSE
;
2986 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2988 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2991 * The first segment requires special handling
2995 ULONG_PTR VirtualAddress
;
2996 ULONG_PTR VirtualOffset
;
2998 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3000 /* Round down the virtual address to the nearest page */
3001 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3003 /* Round up the virtual size to the nearest page */
3004 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3005 EffectiveSegment
->VirtualAddress
;
3007 /* Adjust the raw address and size */
3008 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3010 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3016 * Garbage in, garbage out: unaligned base addresses make the file
3017 * offset point in curious and odd places, but that's what we were
3020 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3021 EffectiveSegment
->RawLength
+= VirtualOffset
;
3025 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3026 ULONG_PTR EndOfEffectiveSegment
;
3028 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3029 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3032 * The current segment begins exactly where the current effective
3033 * segment ended, therefore beginning a new effective segment
3035 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3038 ASSERT(LastSegment
<= i
);
3039 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3041 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3043 if (LastSegment
!= i
)
3046 * Copy the current segment. If necessary, the effective segment
3047 * will be expanded later
3049 *EffectiveSegment
= *Segment
;
3053 * Page-align the virtual size. We know for sure the virtual address
3056 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3057 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3060 * The current segment is still part of the current effective segment:
3061 * extend the effective segment to reflect this
3063 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3065 static const ULONG FlagsToProtection
[16] =
3073 PAGE_EXECUTE_READWRITE
,
3074 PAGE_EXECUTE_READWRITE
,
3079 PAGE_EXECUTE_WRITECOPY
,
3080 PAGE_EXECUTE_WRITECOPY
,
3081 PAGE_EXECUTE_WRITECOPY
,
3082 PAGE_EXECUTE_WRITECOPY
3085 unsigned ProtectionFlags
;
3088 * Extend the file size
3091 /* Unaligned segments must be contiguous within the file */
3092 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3093 EffectiveSegment
->RawLength
))
3098 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3101 * Extend the virtual size
3103 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3105 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3106 EffectiveSegment
->VirtualAddress
;
3109 * Merge the protection
3111 EffectiveSegment
->Protection
|= Segment
->Protection
;
3113 /* Clean up redundance */
3114 ProtectionFlags
= 0;
3116 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3117 ProtectionFlags
|= 1 << 0;
3119 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3120 ProtectionFlags
|= 1 << 1;
3122 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3123 ProtectionFlags
|= 1 << 2;
3125 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3126 ProtectionFlags
|= 1 << 3;
3128 ASSERT(ProtectionFlags
< 16);
3129 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3131 /* If a segment was required to be shared and cannot, fail */
3132 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3133 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3139 * We assume no holes between segments at this point
3143 KeBugCheck(MEMORY_MANAGEMENT
);
3147 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3153 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3154 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3156 LARGE_INTEGER Offset
;
3158 PVOID FileHeaderBuffer
;
3159 ULONG FileHeaderSize
;
3161 ULONG OldNrSegments
;
3166 * Read the beginning of the file (2 pages). Should be enough to contain
3167 * all (or most) of the headers
3169 Offset
.QuadPart
= 0;
3171 /* FIXME: use FileObject instead of FileHandle */
3172 Status
= ExeFmtpReadFile (FileHandle
,
3179 if (!NT_SUCCESS(Status
))
3182 if (FileHeaderSize
== 0)
3184 ExFreePool(FileHeaderBuffer
);
3185 return STATUS_UNSUCCESSFUL
;
3189 * Look for a loader that can handle this executable
3191 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3193 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3196 /* FIXME: use FileObject instead of FileHandle */
3197 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3203 ExeFmtpAllocateSegments
);
3205 if (!NT_SUCCESS(Status
))
3207 if (ImageSectionObject
->Segments
)
3209 ExFreePool(ImageSectionObject
->Segments
);
3210 ImageSectionObject
->Segments
= NULL
;
3214 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3218 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3221 * No loader handled the format
3223 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3225 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3226 ASSERT(!NT_SUCCESS(Status
));
3229 if (!NT_SUCCESS(Status
))
3232 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3237 /* FIXME? are these values platform-dependent? */
3238 if(ImageSectionObject
->StackReserve
== 0)
3239 ImageSectionObject
->StackReserve
= 0x40000;
3241 if(ImageSectionObject
->StackCommit
== 0)
3242 ImageSectionObject
->StackCommit
= 0x1000;
3244 if(ImageSectionObject
->ImageBase
== 0)
3246 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3247 ImageSectionObject
->ImageBase
= 0x10000000;
3249 ImageSectionObject
->ImageBase
= 0x00400000;
3253 * And now the fun part: fixing the segments
3256 /* Sort them by virtual address */
3257 MmspSortSegments(ImageSectionObject
, Flags
);
3259 /* Ensure they don't overlap in memory */
3260 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3261 return STATUS_INVALID_IMAGE_FORMAT
;
3263 /* Ensure they are aligned */
3264 OldNrSegments
= ImageSectionObject
->NrSegments
;
3266 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3267 return STATUS_INVALID_IMAGE_FORMAT
;
3269 /* Trim them if the alignment phase merged some of them */
3270 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3272 PMM_SECTION_SEGMENT Segments
;
3273 SIZE_T SizeOfSegments
;
3275 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3277 Segments
= ExAllocatePoolWithTag(PagedPool
,
3279 TAG_MM_SECTION_SEGMENT
);
3281 if (Segments
== NULL
)
3282 return STATUS_INSUFFICIENT_RESOURCES
;
3284 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3285 ExFreePool(ImageSectionObject
->Segments
);
3286 ImageSectionObject
->Segments
= Segments
;
3289 /* And finish their initialization */
3290 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3292 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3293 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3295 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3296 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3299 ASSERT(NT_SUCCESS(Status
));
3304 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3305 ACCESS_MASK DesiredAccess
,
3306 POBJECT_ATTRIBUTES ObjectAttributes
,
3307 PLARGE_INTEGER UMaximumSize
,
3308 ULONG SectionPageProtection
,
3309 ULONG AllocationAttributes
,
3312 PROS_SECTION_OBJECT Section
;
3314 PFILE_OBJECT FileObject
;
3315 PMM_SECTION_SEGMENT SectionSegments
;
3316 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3318 ULONG FileAccess
= 0;
3321 * Specifying a maximum size is meaningless for an image section
3323 if (UMaximumSize
!= NULL
)
3325 return(STATUS_INVALID_PARAMETER_4
);
3329 * Check file access required
3331 if (SectionPageProtection
& PAGE_READWRITE
||
3332 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3334 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3338 FileAccess
= FILE_READ_DATA
;
3342 * Reference the file handle
3344 Status
= ObReferenceObjectByHandle(FileHandle
,
3347 ExGetPreviousMode(),
3348 (PVOID
*)(PVOID
)&FileObject
,
3351 if (!NT_SUCCESS(Status
))
3357 * Create the section
3359 Status
= ObCreateObject (ExGetPreviousMode(),
3360 MmSectionObjectType
,
3362 ExGetPreviousMode(),
3364 sizeof(ROS_SECTION_OBJECT
),
3367 (PVOID
*)(PVOID
)&Section
);
3368 if (!NT_SUCCESS(Status
))
3370 ObDereferenceObject(FileObject
);
3377 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3378 Section
->SectionPageProtection
= SectionPageProtection
;
3379 Section
->AllocationAttributes
= AllocationAttributes
;
3382 * Initialized caching for this file object if previously caching
3383 * was initialized for the same on disk file
3385 Status
= CcTryToInitializeFileCache(FileObject
);
3387 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3389 NTSTATUS StatusExeFmt
;
3391 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3392 if (ImageSectionObject
== NULL
)
3394 ObDereferenceObject(FileObject
);
3395 ObDereferenceObject(Section
);
3396 return(STATUS_NO_MEMORY
);
3399 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3401 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3403 if (!NT_SUCCESS(StatusExeFmt
))
3405 if(ImageSectionObject
->Segments
!= NULL
)
3406 ExFreePool(ImageSectionObject
->Segments
);
3408 ExFreePool(ImageSectionObject
);
3409 ObDereferenceObject(Section
);
3410 ObDereferenceObject(FileObject
);
3411 return(StatusExeFmt
);
3414 Section
->ImageSection
= ImageSectionObject
;
3415 ASSERT(ImageSectionObject
->Segments
);
3420 Status
= MmspWaitForFileLock(FileObject
);
3421 if (!NT_SUCCESS(Status
))
3423 ExFreePool(ImageSectionObject
->Segments
);
3424 ExFreePool(ImageSectionObject
);
3425 ObDereferenceObject(Section
);
3426 ObDereferenceObject(FileObject
);
3430 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3431 ImageSectionObject
, NULL
))
3434 * An other thread has initialized the same image in the background
3436 ExFreePool(ImageSectionObject
->Segments
);
3437 ExFreePool(ImageSectionObject
);
3438 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3439 Section
->ImageSection
= ImageSectionObject
;
3440 SectionSegments
= ImageSectionObject
->Segments
;
3442 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3444 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3448 Status
= StatusExeFmt
;
3455 Status
= MmspWaitForFileLock(FileObject
);
3456 if (Status
!= STATUS_SUCCESS
)
3458 ObDereferenceObject(Section
);
3459 ObDereferenceObject(FileObject
);
3463 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3464 Section
->ImageSection
= ImageSectionObject
;
3465 SectionSegments
= ImageSectionObject
->Segments
;
3468 * Otherwise just reference all the section segments
3470 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3472 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3475 Status
= STATUS_SUCCESS
;
3477 Section
->FileObject
= FileObject
;
3478 CcRosReferenceCache(FileObject
);
3479 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3480 *SectionObject
= Section
;
3488 NtCreateSection (OUT PHANDLE SectionHandle
,
3489 IN ACCESS_MASK DesiredAccess
,
3490 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3491 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3492 IN ULONG SectionPageProtection OPTIONAL
,
3493 IN ULONG AllocationAttributes
,
3494 IN HANDLE FileHandle OPTIONAL
)
3496 LARGE_INTEGER SafeMaximumSize
;
3497 PVOID SectionObject
;
3498 KPROCESSOR_MODE PreviousMode
;
3499 NTSTATUS Status
= STATUS_SUCCESS
;
3501 PreviousMode
= ExGetPreviousMode();
3503 if(PreviousMode
!= KernelMode
)
3507 if (MaximumSize
!= NULL
)
3509 /* make a copy on the stack */
3510 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3511 MaximumSize
= &SafeMaximumSize
;
3513 ProbeForWriteHandle(SectionHandle
);
3515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3517 Status
= _SEH2_GetExceptionCode();
3521 if(!NT_SUCCESS(Status
))
3527 Status
= MmCreateSection(&SectionObject
,
3531 SectionPageProtection
,
3532 AllocationAttributes
,
3535 if (NT_SUCCESS(Status
))
3537 Status
= ObInsertObject ((PVOID
)SectionObject
,
3549 /**********************************************************************
3567 NtOpenSection(PHANDLE SectionHandle
,
3568 ACCESS_MASK DesiredAccess
,
3569 POBJECT_ATTRIBUTES ObjectAttributes
)
3572 KPROCESSOR_MODE PreviousMode
;
3573 NTSTATUS Status
= STATUS_SUCCESS
;
3575 PreviousMode
= ExGetPreviousMode();
3577 if(PreviousMode
!= KernelMode
)
3581 ProbeForWriteHandle(SectionHandle
);
3583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3585 Status
= _SEH2_GetExceptionCode();
3589 if(!NT_SUCCESS(Status
))
3595 Status
= ObOpenObjectByName(ObjectAttributes
,
3596 MmSectionObjectType
,
3603 if(NT_SUCCESS(Status
))
3607 *SectionHandle
= hSection
;
3609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3611 Status
= _SEH2_GetExceptionCode();
3620 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3621 PROS_SECTION_OBJECT Section
,
3622 PMM_SECTION_SEGMENT Segment
,
3627 ULONG AllocationType
)
3631 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3633 BoundaryAddressMultiple
.QuadPart
= 0;
3635 Status
= MmCreateMemoryArea(AddressSpace
,
3636 MEMORY_AREA_SECTION_VIEW
,
3643 BoundaryAddressMultiple
);
3644 if (!NT_SUCCESS(Status
))
3646 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3647 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3651 ObReferenceObject((PVOID
)Section
);
3653 MArea
->Data
.SectionData
.Segment
= Segment
;
3654 MArea
->Data
.SectionData
.Section
= Section
;
3655 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3656 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3657 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3658 ViewSize
, 0, Protect
);
3660 return(STATUS_SUCCESS
);
3664 /**********************************************************************
3666 * NtMapViewOfSection
3669 * Maps a view of a section into the virtual address space of a
3674 * Handle of the section.
3677 * Handle of the process.
3680 * Desired base address (or NULL) on entry;
3681 * Actual base address of the view on exit.
3684 * Number of high order address bits that must be zero.
3687 * Size in bytes of the initially committed section of
3691 * Offset in bytes from the beginning of the section
3692 * to the beginning of the view.
3695 * Desired length of map (or zero to map all) on entry
3696 * Actual length mapped on exit.
3698 * InheritDisposition
3699 * Specified how the view is to be shared with
3703 * Type of allocation for the pages.
3706 * Protection for the committed region of the view.
3714 NtMapViewOfSection(IN HANDLE SectionHandle
,
3715 IN HANDLE ProcessHandle
,
3716 IN OUT PVOID
* BaseAddress OPTIONAL
,
3717 IN ULONG_PTR ZeroBits OPTIONAL
,
3718 IN SIZE_T CommitSize
,
3719 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3720 IN OUT PSIZE_T ViewSize
,
3721 IN SECTION_INHERIT InheritDisposition
,
3722 IN ULONG AllocationType OPTIONAL
,
3725 PVOID SafeBaseAddress
;
3726 LARGE_INTEGER SafeSectionOffset
;
3727 SIZE_T SafeViewSize
;
3728 PROS_SECTION_OBJECT Section
;
3730 KPROCESSOR_MODE PreviousMode
;
3731 PMMSUPPORT AddressSpace
;
3732 NTSTATUS Status
= STATUS_SUCCESS
;
3734 ACCESS_MASK DesiredAccess
;
3737 * Check the protection
3739 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3741 return STATUS_INVALID_PARAMETER_10
;
3744 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3745 if (tmpProtect
!= PAGE_NOACCESS
&&
3746 tmpProtect
!= PAGE_READONLY
&&
3747 tmpProtect
!= PAGE_READWRITE
&&
3748 tmpProtect
!= PAGE_WRITECOPY
&&
3749 tmpProtect
!= PAGE_EXECUTE
&&
3750 tmpProtect
!= PAGE_EXECUTE_READ
&&
3751 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3752 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3754 return STATUS_INVALID_PAGE_PROTECTION
;
3757 PreviousMode
= ExGetPreviousMode();
3759 if(PreviousMode
!= KernelMode
)
3761 SafeBaseAddress
= NULL
;
3762 SafeSectionOffset
.QuadPart
= 0;
3767 if(BaseAddress
!= NULL
)
3769 ProbeForWritePointer(BaseAddress
);
3770 SafeBaseAddress
= *BaseAddress
;
3772 if(SectionOffset
!= NULL
)
3774 ProbeForWriteLargeInteger(SectionOffset
);
3775 SafeSectionOffset
= *SectionOffset
;
3777 ProbeForWriteSize_t(ViewSize
);
3778 SafeViewSize
= *ViewSize
;
3780 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3782 Status
= _SEH2_GetExceptionCode();
3786 if(!NT_SUCCESS(Status
))
3793 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3794 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3795 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3798 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3800 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3801 PROCESS_VM_OPERATION
,
3804 (PVOID
*)(PVOID
)&Process
,
3806 if (!NT_SUCCESS(Status
))
3811 AddressSpace
= &Process
->Vm
;
3813 /* Convert NT Protection Attr to Access Mask */
3814 if (Protect
== PAGE_READONLY
)
3816 DesiredAccess
= SECTION_MAP_READ
;
3818 else if (Protect
== PAGE_READWRITE
)
3820 DesiredAccess
= SECTION_MAP_WRITE
;
3822 else if (Protect
== PAGE_WRITECOPY
)
3824 DesiredAccess
= SECTION_QUERY
;
3826 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3829 DesiredAccess
= SECTION_MAP_READ
;
3832 Status
= ObReferenceObjectByHandle(SectionHandle
,
3834 MmSectionObjectType
,
3836 (PVOID
*)(PVOID
)&Section
,
3838 if (!(NT_SUCCESS(Status
)))
3840 DPRINT("ObReference failed rc=%x\n",Status
);
3841 ObDereferenceObject(Process
);
3845 Status
= MmMapViewOfSection(Section
,
3847 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3850 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3851 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3856 /* Check if this is an image for the current process */
3857 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3858 (Process
== PsGetCurrentProcess()) &&
3859 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3861 /* Notify the debugger */
3862 DbgkMapViewOfSection(Section
,
3864 SafeSectionOffset
.LowPart
,
3868 ObDereferenceObject(Section
);
3869 ObDereferenceObject(Process
);
3871 if(NT_SUCCESS(Status
))
3873 /* copy parameters back to the caller */
3876 if(BaseAddress
!= NULL
)
3878 *BaseAddress
= SafeBaseAddress
;
3880 if(SectionOffset
!= NULL
)
3882 *SectionOffset
= SafeSectionOffset
;
3884 if(ViewSize
!= NULL
)
3886 *ViewSize
= SafeViewSize
;
3889 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3891 Status
= _SEH2_GetExceptionCode();
3900 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3901 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3904 PFILE_OBJECT FileObject
;
3907 SWAPENTRY SavedSwapEntry
;
3910 PROS_SECTION_OBJECT Section
;
3911 PMM_SECTION_SEGMENT Segment
;
3912 PMMSUPPORT AddressSpace
;
3915 AddressSpace
= (PMMSUPPORT
)Context
;
3916 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3918 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3920 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3921 MemoryArea
->Data
.SectionData
.ViewOffset
;
3923 Section
= MemoryArea
->Data
.SectionData
.Section
;
3924 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3926 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3930 MmUnlockSectionSegment(Segment
);
3931 MmUnlockAddressSpace(AddressSpace
);
3933 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3934 if (Status
!= STATUS_SUCCESS
)
3936 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3937 KeBugCheck(MEMORY_MANAGEMENT
);
3940 MmLockAddressSpace(AddressSpace
);
3941 MmLockSectionSegment(Segment
);
3942 MmspCompleteAndReleasePageOp(PageOp
);
3943 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3946 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3949 * For a dirty, datafile, non-private page mark it as dirty in the
3952 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3954 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3956 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3957 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3958 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3959 ASSERT(SwapEntry
== 0);
3968 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3970 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3971 KeBugCheck(MEMORY_MANAGEMENT
);
3973 MmFreeSwapPage(SwapEntry
);
3977 if (IS_SWAP_FROM_SSE(Entry
) ||
3978 Page
!= PFN_FROM_SSE(Entry
))
3983 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3985 DPRINT1("Found a private page in a pagefile section.\n");
3986 KeBugCheck(MEMORY_MANAGEMENT
);
3989 * Just dereference private pages
3991 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3992 if (SavedSwapEntry
!= 0)
3994 MmFreeSwapPage(SavedSwapEntry
);
3995 MmSetSavedSwapEntryPage(Page
, 0);
3997 MmDeleteRmap(Page
, Process
, Address
);
3998 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4002 MmDeleteRmap(Page
, Process
, Address
);
4003 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4009 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4013 PMEMORY_AREA MemoryArea
;
4014 PROS_SECTION_OBJECT Section
;
4015 PMM_SECTION_SEGMENT Segment
;
4016 PLIST_ENTRY CurrentEntry
;
4017 PMM_REGION CurrentRegion
;
4018 PLIST_ENTRY RegionListHead
;
4020 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4022 if (MemoryArea
== NULL
)
4024 return(STATUS_UNSUCCESSFUL
);
4027 MemoryArea
->DeleteInProgress
= TRUE
;
4028 Section
= MemoryArea
->Data
.SectionData
.Section
;
4029 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4031 MmLockSectionSegment(Segment
);
4033 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4034 while (!IsListEmpty(RegionListHead
))
4036 CurrentEntry
= RemoveHeadList(RegionListHead
);
4037 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4038 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4041 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4043 Status
= MmFreeMemoryArea(AddressSpace
,
4050 Status
= MmFreeMemoryArea(AddressSpace
,
4055 MmUnlockSectionSegment(Segment
);
4056 ObDereferenceObject(Section
);
4057 return(STATUS_SUCCESS
);
4064 MmUnmapViewOfSection(PEPROCESS Process
,
4068 PMEMORY_AREA MemoryArea
;
4069 PMMSUPPORT AddressSpace
;
4070 PROS_SECTION_OBJECT Section
;
4073 PVOID ImageBaseAddress
= 0;
4075 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4076 Process
, BaseAddress
);
4080 AddressSpace
= &Process
->Vm
;
4082 MmLockAddressSpace(AddressSpace
);
4083 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4085 if (MemoryArea
== NULL
||
4086 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4087 MemoryArea
->DeleteInProgress
)
4089 MmUnlockAddressSpace(AddressSpace
);
4090 return STATUS_NOT_MAPPED_VIEW
;
4093 MemoryArea
->DeleteInProgress
= TRUE
;
4095 while (MemoryArea
->PageOpCount
)
4097 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4101 Offset
-= PAGE_SIZE
;
4102 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4103 MemoryArea
->Data
.SectionData
.Segment
,
4104 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4107 MmUnlockAddressSpace(AddressSpace
);
4108 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4109 if (Status
!= STATUS_SUCCESS
)
4111 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4112 KeBugCheck(MEMORY_MANAGEMENT
);
4114 MmLockAddressSpace(AddressSpace
);
4115 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4117 if (MemoryArea
== NULL
||
4118 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4120 MmUnlockAddressSpace(AddressSpace
);
4121 return STATUS_NOT_MAPPED_VIEW
;
4128 Section
= MemoryArea
->Data
.SectionData
.Section
;
4130 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4134 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4135 PMM_SECTION_SEGMENT SectionSegments
;
4136 PMM_SECTION_SEGMENT Segment
;
4138 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4139 ImageSectionObject
= Section
->ImageSection
;
4140 SectionSegments
= ImageSectionObject
->Segments
;
4141 NrSegments
= ImageSectionObject
->NrSegments
;
4143 /* Search for the current segment within the section segments
4144 * and calculate the image base address */
4145 for (i
= 0; i
< NrSegments
; i
++)
4147 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4149 if (Segment
== &SectionSegments
[i
])
4151 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4156 if (i
>= NrSegments
)
4158 KeBugCheck(MEMORY_MANAGEMENT
);
4161 for (i
= 0; i
< NrSegments
; i
++)
4163 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4165 PVOID SBaseAddress
= (PVOID
)
4166 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4168 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4174 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4177 MmUnlockAddressSpace(AddressSpace
);
4179 /* Notify debugger */
4180 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4182 return(STATUS_SUCCESS
);
4185 /**********************************************************************
4187 * NtUnmapViewOfSection
4202 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4206 KPROCESSOR_MODE PreviousMode
;
4209 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4210 ProcessHandle
, BaseAddress
);
4212 PreviousMode
= ExGetPreviousMode();
4214 DPRINT("Referencing process\n");
4215 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4216 PROCESS_VM_OPERATION
,
4219 (PVOID
*)(PVOID
)&Process
,
4221 if (!NT_SUCCESS(Status
))
4223 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4227 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4229 ObDereferenceObject(Process
);
4236 * Queries the information of a section object.
4238 * @param SectionHandle
4239 * Handle to the section object. It must be opened with SECTION_QUERY
4241 * @param SectionInformationClass
4242 * Index to a certain information structure. Can be either
4243 * SectionBasicInformation or SectionImageInformation. The latter
4244 * is valid only for sections that were created with the SEC_IMAGE
4246 * @param SectionInformation
4247 * Caller supplies storage for resulting information.
4249 * Size of the supplied storage.
4250 * @param ResultLength
4258 NtQuerySection(IN HANDLE SectionHandle
,
4259 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4260 OUT PVOID SectionInformation
,
4261 IN ULONG SectionInformationLength
,
4262 OUT PULONG ResultLength OPTIONAL
)
4264 PROS_SECTION_OBJECT Section
;
4265 KPROCESSOR_MODE PreviousMode
;
4266 NTSTATUS Status
= STATUS_SUCCESS
;
4269 PreviousMode
= ExGetPreviousMode();
4271 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4273 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4275 SectionInformationLength
,
4279 if(!NT_SUCCESS(Status
))
4281 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4285 Status
= ObReferenceObjectByHandle(SectionHandle
,
4287 MmSectionObjectType
,
4289 (PVOID
*)(PVOID
)&Section
,
4291 if (NT_SUCCESS(Status
))
4293 switch (SectionInformationClass
)
4295 case SectionBasicInformation
:
4297 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4301 Sbi
->Attributes
= Section
->AllocationAttributes
;
4302 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4304 Sbi
->BaseAddress
= 0;
4305 Sbi
->Size
.QuadPart
= 0;
4309 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4310 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4313 if (ResultLength
!= NULL
)
4315 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4317 Status
= STATUS_SUCCESS
;
4319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4321 Status
= _SEH2_GetExceptionCode();
4328 case SectionImageInformation
:
4330 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4334 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4335 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4337 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4338 ImageSectionObject
= Section
->ImageSection
;
4340 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4341 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4342 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4343 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4344 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4345 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4346 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4347 Sii
->Machine
= ImageSectionObject
->Machine
;
4348 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4351 if (ResultLength
!= NULL
)
4353 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4355 Status
= STATUS_SUCCESS
;
4357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4359 Status
= _SEH2_GetExceptionCode();
4367 ObDereferenceObject(Section
);
4375 * Extends size of file backed section.
4377 * @param SectionHandle
4378 * Handle to the section object. It must be opened with
4379 * SECTION_EXTEND_SIZE access.
4380 * @param NewMaximumSize
4381 * New maximum size of the section in bytes.
4385 * @todo Move the actual code to internal function MmExtendSection.
4389 NtExtendSection(IN HANDLE SectionHandle
,
4390 IN PLARGE_INTEGER NewMaximumSize
)
4392 LARGE_INTEGER SafeNewMaximumSize
;
4393 PROS_SECTION_OBJECT Section
;
4394 KPROCESSOR_MODE PreviousMode
;
4395 NTSTATUS Status
= STATUS_SUCCESS
;
4397 PreviousMode
= ExGetPreviousMode();
4399 if(PreviousMode
!= KernelMode
)
4403 /* make a copy on the stack */
4404 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4405 NewMaximumSize
= &SafeNewMaximumSize
;
4407 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4409 Status
= _SEH2_GetExceptionCode();
4413 if(!NT_SUCCESS(Status
))
4419 Status
= ObReferenceObjectByHandle(SectionHandle
,
4420 SECTION_EXTEND_SIZE
,
4421 MmSectionObjectType
,
4425 if (!NT_SUCCESS(Status
))
4430 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4432 ObDereferenceObject(Section
);
4433 return STATUS_INVALID_PARAMETER
;
4437 * - Acquire file extneding resource.
4438 * - Check if we're not resizing the section below it's actual size!
4439 * - Extend segments if needed.
4440 * - Set file information (FileAllocationInformation) to the new size.
4441 * - Release file extending resource.
4444 ObDereferenceObject(Section
);
4446 return STATUS_NOT_IMPLEMENTED
;
4450 /**********************************************************************
4452 * MmAllocateSection@4
4462 * Code taken from ntoskrnl/mm/special.c.
4467 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4472 PMMSUPPORT AddressSpace
;
4473 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4475 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4477 BoundaryAddressMultiple
.QuadPart
= 0;
4479 AddressSpace
= MmGetKernelAddressSpace();
4480 Result
= BaseAddress
;
4481 MmLockAddressSpace(AddressSpace
);
4482 Status
= MmCreateMemoryArea (AddressSpace
,
4490 BoundaryAddressMultiple
);
4491 MmUnlockAddressSpace(AddressSpace
);
4493 if (!NT_SUCCESS(Status
))
4497 DPRINT("Result %p\n",Result
);
4499 /* Create a virtual mapping for this memory area */
4500 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4502 return ((PVOID
)Result
);
4506 /**********************************************************************
4508 * MmMapViewOfSection
4511 * Maps a view of a section into the virtual address space of a
4516 * Pointer to the section object.
4519 * Pointer to the process.
4522 * Desired base address (or NULL) on entry;
4523 * Actual base address of the view on exit.
4526 * Number of high order address bits that must be zero.
4529 * Size in bytes of the initially committed section of
4533 * Offset in bytes from the beginning of the section
4534 * to the beginning of the view.
4537 * Desired length of map (or zero to map all) on entry
4538 * Actual length mapped on exit.
4540 * InheritDisposition
4541 * Specified how the view is to be shared with
4545 * Type of allocation for the pages.
4548 * Protection for the committed region of the view.
4556 MmMapViewOfSection(IN PVOID SectionObject
,
4557 IN PEPROCESS Process
,
4558 IN OUT PVOID
*BaseAddress
,
4559 IN ULONG_PTR ZeroBits
,
4560 IN SIZE_T CommitSize
,
4561 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4562 IN OUT PSIZE_T ViewSize
,
4563 IN SECTION_INHERIT InheritDisposition
,
4564 IN ULONG AllocationType
,
4567 PROS_SECTION_OBJECT Section
;
4568 PMMSUPPORT AddressSpace
;
4570 NTSTATUS Status
= STATUS_SUCCESS
;
4574 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4576 return STATUS_INVALID_PAGE_PROTECTION
;
4580 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4581 AddressSpace
= &Process
->Vm
;
4583 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4585 MmLockAddressSpace(AddressSpace
);
4587 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4591 ULONG_PTR ImageBase
;
4593 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4594 PMM_SECTION_SEGMENT SectionSegments
;
4596 ImageSectionObject
= Section
->ImageSection
;
4597 SectionSegments
= ImageSectionObject
->Segments
;
4598 NrSegments
= ImageSectionObject
->NrSegments
;
4601 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4604 ImageBase
= ImageSectionObject
->ImageBase
;
4608 for (i
= 0; i
< NrSegments
; i
++)
4610 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4612 ULONG_PTR MaxExtent
;
4613 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4614 SectionSegments
[i
].Length
;
4615 ImageSize
= max(ImageSize
, MaxExtent
);
4619 ImageSectionObject
->ImageSize
= ImageSize
;
4621 /* Check there is enough space to map the section at that point. */
4622 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4623 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4625 /* Fail if the user requested a fixed base address. */
4626 if ((*BaseAddress
) != NULL
)
4628 MmUnlockAddressSpace(AddressSpace
);
4629 return(STATUS_UNSUCCESSFUL
);
4631 /* Otherwise find a gap to map the image. */
4632 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4635 MmUnlockAddressSpace(AddressSpace
);
4636 return(STATUS_UNSUCCESSFUL
);
4640 for (i
= 0; i
< NrSegments
; i
++)
4642 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4644 PVOID SBaseAddress
= (PVOID
)
4645 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4646 MmLockSectionSegment(&SectionSegments
[i
]);
4647 Status
= MmMapViewOfSegment(AddressSpace
,
4649 &SectionSegments
[i
],
4651 SectionSegments
[i
].Length
,
4652 SectionSegments
[i
].Protection
,
4655 MmUnlockSectionSegment(&SectionSegments
[i
]);
4656 if (!NT_SUCCESS(Status
))
4658 MmUnlockAddressSpace(AddressSpace
);
4664 *BaseAddress
= (PVOID
)ImageBase
;
4668 /* check for write access */
4669 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4670 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4672 MmUnlockAddressSpace(AddressSpace
);
4673 return STATUS_SECTION_PROTECTION
;
4675 /* check for read access */
4676 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4677 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4679 MmUnlockAddressSpace(AddressSpace
);
4680 return STATUS_SECTION_PROTECTION
;
4682 /* check for execute access */
4683 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4684 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4686 MmUnlockAddressSpace(AddressSpace
);
4687 return STATUS_SECTION_PROTECTION
;
4690 if (ViewSize
== NULL
)
4692 /* Following this pointer would lead to us to the dark side */
4693 /* What to do? Bugcheck? Return status? Do the mambo? */
4694 KeBugCheck(MEMORY_MANAGEMENT
);
4697 if (SectionOffset
== NULL
)
4703 ViewOffset
= SectionOffset
->u
.LowPart
;
4706 if ((ViewOffset
% PAGE_SIZE
) != 0)
4708 MmUnlockAddressSpace(AddressSpace
);
4709 return(STATUS_MAPPED_ALIGNMENT
);
4712 if ((*ViewSize
) == 0)
4714 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4716 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4718 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4721 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4723 MmLockSectionSegment(Section
->Segment
);
4724 Status
= MmMapViewOfSegment(AddressSpace
,
4731 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4732 MmUnlockSectionSegment(Section
->Segment
);
4733 if (!NT_SUCCESS(Status
))
4735 MmUnlockAddressSpace(AddressSpace
);
4740 MmUnlockAddressSpace(AddressSpace
);
4742 return(STATUS_SUCCESS
);
4749 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4750 IN PLARGE_INTEGER NewFileSize
)
4752 /* Check whether an ImageSectionObject exists */
4753 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4755 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4759 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4761 PMM_SECTION_SEGMENT Segment
;
4763 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4766 if (Segment
->ReferenceCount
!= 0)
4768 /* Check size of file */
4769 if (SectionObjectPointer
->SharedCacheMap
)
4771 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4772 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4780 /* Something must gone wrong
4781 * how can we have a Section but no
4783 DPRINT1("ERROR: DataSectionObject without reference!\n");
4787 DPRINT("FIXME: didn't check for outstanding write probes\n");
4797 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4807 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4808 IN MMFLUSH_TYPE FlushType
)
4812 case MmFlushForDelete
:
4813 if (SectionObjectPointer
->ImageSectionObject
||
4814 SectionObjectPointer
->DataSectionObject
)
4818 CcRosSetRemoveOnClose(SectionObjectPointer
);
4820 case MmFlushForWrite
:
4830 MmForceSectionClosed (
4831 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4832 IN BOOLEAN DelayClose
)
4843 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4844 OUT PVOID
* MappedBase
,
4845 IN OUT PULONG ViewSize
)
4847 PROS_SECTION_OBJECT Section
;
4848 PMMSUPPORT AddressSpace
;
4851 DPRINT("MmMapViewInSystemSpace() called\n");
4853 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4854 AddressSpace
= MmGetKernelAddressSpace();
4856 MmLockAddressSpace(AddressSpace
);
4859 if ((*ViewSize
) == 0)
4861 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4863 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4865 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4868 MmLockSectionSegment(Section
->Segment
);
4871 Status
= MmMapViewOfSegment(AddressSpace
,
4880 MmUnlockSectionSegment(Section
->Segment
);
4881 MmUnlockAddressSpace(AddressSpace
);
4891 MmMapViewInSessionSpace (
4893 OUT PVOID
*MappedBase
,
4894 IN OUT PSIZE_T ViewSize
4898 return STATUS_NOT_IMPLEMENTED
;
4906 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4908 PMMSUPPORT AddressSpace
;
4911 DPRINT("MmUnmapViewInSystemSpace() called\n");
4913 AddressSpace
= MmGetKernelAddressSpace();
4915 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4925 MmUnmapViewInSessionSpace (
4930 return STATUS_NOT_IMPLEMENTED
;
4937 MmSetBankedSection (ULONG Unknown0
,
4945 return (STATUS_NOT_IMPLEMENTED
);
4949 /**********************************************************************
4954 * Creates a section object.
4957 * SectionObject (OUT)
4958 * Caller supplied storage for the resulting pointer
4959 * to a SECTION_OBJECT instance;
4962 * Specifies the desired access to the section can be a
4964 * STANDARD_RIGHTS_REQUIRED |
4966 * SECTION_MAP_WRITE |
4967 * SECTION_MAP_READ |
4968 * SECTION_MAP_EXECUTE
4970 * ObjectAttributes [OPTIONAL]
4971 * Initialized attributes for the object can be used
4972 * to create a named section;
4975 * Maximizes the size of the memory section. Must be
4976 * non-NULL for a page-file backed section.
4977 * If value specified for a mapped file and the file is
4978 * not large enough, file will be extended.
4980 * SectionPageProtection
4981 * Can be a combination of:
4987 * AllocationAttributes
4988 * Can be a combination of:
4993 * Handle to a file to create a section mapped to a file
4994 * instead of a memory backed section;
5005 MmCreateSection (OUT PVOID
* Section
,
5006 IN ACCESS_MASK DesiredAccess
,
5007 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5008 IN PLARGE_INTEGER MaximumSize
,
5009 IN ULONG SectionPageProtection
,
5010 IN ULONG AllocationAttributes
,
5011 IN HANDLE FileHandle OPTIONAL
,
5012 IN PFILE_OBJECT File OPTIONAL
)
5015 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5018 * Check the protection
5020 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5021 if (Protection
!= PAGE_READONLY
&&
5022 Protection
!= PAGE_READWRITE
&&
5023 Protection
!= PAGE_WRITECOPY
&&
5024 Protection
!= PAGE_EXECUTE
&&
5025 Protection
!= PAGE_EXECUTE_READ
&&
5026 Protection
!= PAGE_EXECUTE_READWRITE
&&
5027 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5029 return STATUS_INVALID_PAGE_PROTECTION
;
5032 if (AllocationAttributes
& SEC_IMAGE
)
5034 return(MmCreateImageSection(SectionObject
,
5038 SectionPageProtection
,
5039 AllocationAttributes
,
5043 if (FileHandle
!= NULL
)
5045 return(MmCreateDataFileSection(SectionObject
,
5049 SectionPageProtection
,
5050 AllocationAttributes
,
5054 return(MmCreatePageFileSection(SectionObject
,
5058 SectionPageProtection
,
5059 AllocationAttributes
));
5064 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5065 IN OUT PULONG_PTR NumberOfPages
,
5066 IN OUT PULONG_PTR UserPfnArray
)
5069 return STATUS_NOT_IMPLEMENTED
;
5074 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5075 IN ULONG_PTR NumberOfPages
,
5076 IN OUT PULONG_PTR UserPfnArray
)
5079 return STATUS_NOT_IMPLEMENTED
;
5084 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5085 IN ULONG_PTR NumberOfPages
,
5086 IN OUT PULONG_PTR UserPfnArray
)
5089 return STATUS_NOT_IMPLEMENTED
;
5094 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5095 IN OUT PULONG_PTR NumberOfPages
,
5096 IN OUT PULONG_PTR UserPfnArray
)
5099 return STATUS_NOT_IMPLEMENTED
;
5104 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5105 IN PVOID File2MappedAsFile
)
5108 return STATUS_NOT_IMPLEMENTED
;