2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, TAG('M', 'm', ' ', ' '));
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
153 PROS_SECTION_OBJECT Section
;
154 PMEMORY_AREA MemoryArea
;
155 PMMSUPPORT AddressSpace
;
156 POBJECT_NAME_INFORMATION ModuleNameInformation
;
157 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
159 /* Get the MM_AVL_TABLE from EPROCESS */
160 if (Address
>= MmSystemRangeStart
)
162 AddressSpace
= MmGetKernelAddressSpace();
166 AddressSpace
= &PsGetCurrentProcess()->Vm
;
169 /* Lock address space */
170 MmLockAddressSpace(AddressSpace
);
172 /* Locate the memory area for the process by address */
173 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
175 /* Make sure it's a section view type */
176 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
178 /* Get the section pointer to the SECTION_OBJECT */
179 Section
= MemoryArea
->Data
.SectionData
.Section
;
181 /* Unlock address space */
182 MmUnlockAddressSpace(AddressSpace
);
184 /* Get the filename of the section */
185 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
187 if (NT_SUCCESS(Status
))
189 /* Init modulename */
190 RtlCreateUnicodeString(ModuleName
,
191 ModuleNameInformation
->Name
.Buffer
);
193 /* Free temp taged buffer from MmGetFileNameForSection() */
194 ExFreePoolWithTag(ModuleNameInformation
, TAG('M', 'm', ' ', ' '));
195 DPRINT("Found ModuleName %S by address %p\n",
196 ModuleName
->Buffer
,Address
);
201 /* Unlock address space */
202 MmUnlockAddressSpace(AddressSpace
);
208 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
211 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
212 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
213 * RETURNS: Status of the wait.
216 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
218 LARGE_INTEGER Timeout
;
219 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
221 Timeout
.QuadPart
= -100000000LL; // 10 sec
224 Timeout
.QuadPart
= -100000000; // 10 sec
227 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
232 * FUNCTION: Sets the page op completion event and releases the page op.
233 * ARGUMENTS: PMM_PAGEOP.
234 * RETURNS: In shorter time than it takes you to even read this
235 * description, so don't even think about geting a mug of coffee.
238 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
240 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
241 MmReleasePageOp(PageOp
);
246 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
247 * ARGUMENTS: PFILE_OBJECT to wait for.
248 * RETURNS: Status of the wait.
251 MmspWaitForFileLock(PFILE_OBJECT File
)
253 return STATUS_SUCCESS
;
254 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
259 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
262 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
264 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
266 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
268 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
276 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
278 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
280 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
281 PMM_SECTION_SEGMENT SectionSegments
;
285 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
286 NrSegments
= ImageSectionObject
->NrSegments
;
287 SectionSegments
= ImageSectionObject
->Segments
;
288 for (i
= 0; i
< NrSegments
; i
++)
290 if (SectionSegments
[i
].ReferenceCount
!= 0)
292 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
293 SectionSegments
[i
].ReferenceCount
);
294 KeBugCheck(MEMORY_MANAGEMENT
);
296 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
298 ExFreePool(ImageSectionObject
->Segments
);
299 ExFreePool(ImageSectionObject
);
300 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
302 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
304 PMM_SECTION_SEGMENT Segment
;
306 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
309 if (Segment
->ReferenceCount
!= 0)
311 DPRINT1("Data segment still referenced\n");
312 KeBugCheck(MEMORY_MANAGEMENT
);
314 MmFreePageTablesSectionSegment(Segment
);
316 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
322 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
324 ExAcquireFastMutex(&Segment
->Lock
);
329 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
331 ExReleaseFastMutex(&Segment
->Lock
);
336 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
340 PSECTION_PAGE_TABLE Table
;
341 ULONG DirectoryOffset
;
344 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
346 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
350 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
351 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
355 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
356 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
357 TAG_SECTION_PAGE_TABLE
);
360 KeBugCheck(MEMORY_MANAGEMENT
);
362 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
363 DPRINT("Table %x\n", Table
);
366 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
367 Table
->Entry
[TableOffset
] = Entry
;
373 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
376 PSECTION_PAGE_TABLE Table
;
378 ULONG DirectoryOffset
;
381 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
383 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
385 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
389 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
390 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
391 DPRINT("Table %x\n", Table
);
397 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
398 Entry
= Table
->Entry
[TableOffset
];
404 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
409 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
412 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
413 KeBugCheck(MEMORY_MANAGEMENT
);
415 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
417 DPRINT1("Maximum share count reached\n");
418 KeBugCheck(MEMORY_MANAGEMENT
);
420 if (IS_SWAP_FROM_SSE(Entry
))
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
430 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
431 PMM_SECTION_SEGMENT Segment
,
437 BOOLEAN IsDirectMapped
= FALSE
;
439 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
442 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
447 DPRINT1("Zero share count for unshare\n");
448 KeBugCheck(MEMORY_MANAGEMENT
);
450 if (IS_SWAP_FROM_SSE(Entry
))
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
456 * If we reducing the share count of this entry to zero then set the entry
457 * to zero and tell the cache the page is no longer mapped.
459 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
461 PFILE_OBJECT FileObject
;
463 SWAPENTRY SavedSwapEntry
;
465 BOOLEAN IsImageSection
;
468 FileOffset
= Offset
+ Segment
->FileOffset
;
470 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
472 Page
= PFN_FROM_SSE(Entry
);
473 FileObject
= Section
->FileObject
;
474 if (FileObject
!= NULL
&&
475 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
478 if ((FileOffset
% PAGE_SIZE
) == 0 &&
479 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
482 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
483 IsDirectMapped
= TRUE
;
484 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
488 KeBugCheck(MEMORY_MANAGEMENT
);
493 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
494 if (SavedSwapEntry
== 0)
497 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
498 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
502 * Try to page out this page and set the swap entry
503 * within the section segment. There exist no rmap entry
504 * for this page. The pager thread can't page out a
505 * page without a rmap entry.
507 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
511 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
514 MmReleasePageMemoryConsumer(MC_USER
, Page
);
520 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
521 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
529 * We hold all locks. Nobody can do something with the current
530 * process and the current segment (also not within an other process).
533 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
540 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
541 MmSetSavedSwapEntryPage(Page
, 0);
543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
547 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
548 KeBugCheck(MEMORY_MANAGEMENT
);
554 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
556 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
559 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
562 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
565 PCACHE_SEGMENT CacheSeg
;
566 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
567 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
579 MiReadPage(PMEMORY_AREA MemoryArea
,
583 * FUNCTION: Read a page for a section backed memory area.
585 * MemoryArea - Memory area to read the page for.
586 * Offset - Offset of the page to read.
587 * Page - Variable that receives a page contains the read data.
594 PCACHE_SEGMENT CacheSeg
;
595 PFILE_OBJECT FileObject
;
599 BOOLEAN IsImageSection
;
602 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
603 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
604 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
605 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
606 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
610 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
613 * If the file system is letting us go directly to the cache and the
614 * memory area was mapped at an offset in the file which is page aligned
615 * then get the related cache segment.
617 if ((FileOffset
% PAGE_SIZE
) == 0 &&
618 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
619 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
623 * Get the related cache segment; we use a lower level interface than
624 * filesystems do because it is safe for us to use an offset with a
625 * alignment less than the file system block size.
627 Status
= CcRosGetCacheSegment(Bcb
,
633 if (!NT_SUCCESS(Status
))
640 * If the cache segment isn't up to date then call the file
641 * system to read in the data.
643 Status
= ReadCacheSegment(CacheSeg
);
644 if (!NT_SUCCESS(Status
))
646 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
651 * Retrieve the page from the cache segment that we actually want.
653 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
654 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
656 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
663 ULONG CacheSegOffset
;
666 * Allocate a page, this is rather complicated by the possibility
667 * we might have to move other things out of memory
669 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
670 if (!NT_SUCCESS(Status
))
674 Status
= CcRosGetCacheSegment(Bcb
,
680 if (!NT_SUCCESS(Status
))
687 * If the cache segment isn't up to date then call the file
688 * system to read in the data.
690 Status
= ReadCacheSegment(CacheSeg
);
691 if (!NT_SUCCESS(Status
))
693 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
698 Process
= PsGetCurrentProcess();
699 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
700 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
701 Length
= RawLength
- SegOffset
;
702 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
704 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
706 else if (CacheSegOffset
>= PAGE_SIZE
)
708 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
712 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
713 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
714 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
715 Status
= CcRosGetCacheSegment(Bcb
,
716 FileOffset
+ CacheSegOffset
,
721 if (!NT_SUCCESS(Status
))
728 * If the cache segment isn't up to date then call the file
729 * system to read in the data.
731 Status
= ReadCacheSegment(CacheSeg
);
732 if (!NT_SUCCESS(Status
))
734 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
738 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
739 if (Length
< PAGE_SIZE
)
741 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
745 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
748 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
749 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
751 return(STATUS_SUCCESS
);
756 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
757 MEMORY_AREA
* MemoryArea
,
765 PROS_SECTION_OBJECT Section
;
766 PMM_SECTION_SEGMENT Segment
;
772 BOOLEAN HasSwapEntry
;
773 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
776 * There is a window between taking the page fault and locking the
777 * address space when another thread could load the page so we check
780 if (MmIsPagePresent(Process
, Address
))
784 MmLockPage(MmGetPfnForProcess(Process
, Address
));
786 return(STATUS_SUCCESS
);
789 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
790 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
791 + MemoryArea
->Data
.SectionData
.ViewOffset
;
793 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
794 Section
= MemoryArea
->Data
.SectionData
.Section
;
795 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
796 &MemoryArea
->Data
.SectionData
.RegionListHead
,
801 MmLockSectionSegment(Segment
);
804 * Check if this page needs to be mapped COW
806 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
807 (Region
->Protect
== PAGE_READWRITE
||
808 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
810 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
814 Attributes
= Region
->Protect
;
818 * Get or create a page operation descriptor
820 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
823 DPRINT1("MmGetPageOp failed\n");
824 KeBugCheck(MEMORY_MANAGEMENT
);
828 * Check if someone else is already handling this fault, if so wait
831 if (PageOp
->Thread
!= PsGetCurrentThread())
833 MmUnlockSectionSegment(Segment
);
834 MmUnlockAddressSpace(AddressSpace
);
835 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
837 * Check for various strange conditions
839 if (Status
!= STATUS_SUCCESS
)
841 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
842 KeBugCheck(MEMORY_MANAGEMENT
);
844 if (PageOp
->Status
== STATUS_PENDING
)
846 DPRINT1("Woke for page op before completion\n");
847 KeBugCheck(MEMORY_MANAGEMENT
);
849 MmLockAddressSpace(AddressSpace
);
851 * If this wasn't a pagein then restart the operation
853 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
855 MmspCompleteAndReleasePageOp(PageOp
);
856 DPRINT("Address 0x%.8X\n", Address
);
857 return(STATUS_MM_RESTART_OPERATION
);
861 * If the thread handling this fault has failed then we don't retry
863 if (!NT_SUCCESS(PageOp
->Status
))
865 Status
= PageOp
->Status
;
866 MmspCompleteAndReleasePageOp(PageOp
);
867 DPRINT("Address 0x%.8X\n", Address
);
870 MmLockSectionSegment(Segment
);
872 * If the completed fault was for another address space then set the
875 if (!MmIsPagePresent(Process
, Address
))
877 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
878 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
880 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
883 * The page was a private page in another or in our address space
885 MmUnlockSectionSegment(Segment
);
886 MmspCompleteAndReleasePageOp(PageOp
);
887 return(STATUS_MM_RESTART_OPERATION
);
890 Page
= PFN_FROM_SSE(Entry
);
892 MmSharePageEntrySectionSegment(Segment
, Offset
);
894 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
895 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
897 Status
= MmCreateVirtualMapping(Process
,
902 if (!NT_SUCCESS(Status
))
904 DPRINT1("Unable to create virtual mapping\n");
905 KeBugCheck(MEMORY_MANAGEMENT
);
907 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
913 MmUnlockSectionSegment(Segment
);
914 PageOp
->Status
= STATUS_SUCCESS
;
915 MmspCompleteAndReleasePageOp(PageOp
);
916 DPRINT("Address 0x%.8X\n", Address
);
917 return(STATUS_SUCCESS
);
920 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
924 * Must be private page we have swapped out.
931 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
933 DPRINT1("Found a swaped out private page in a pagefile section.\n");
934 KeBugCheck(MEMORY_MANAGEMENT
);
937 MmUnlockSectionSegment(Segment
);
938 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
940 MmUnlockAddressSpace(AddressSpace
);
941 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
942 if (!NT_SUCCESS(Status
))
944 KeBugCheck(MEMORY_MANAGEMENT
);
947 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
951 KeBugCheck(MEMORY_MANAGEMENT
);
953 MmLockAddressSpace(AddressSpace
);
954 Status
= MmCreateVirtualMapping(Process
,
959 if (!NT_SUCCESS(Status
))
961 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
962 KeBugCheck(MEMORY_MANAGEMENT
);
967 * Store the swap entry for later use.
969 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
972 * Add the page to the process's working set
974 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
977 * Finish the operation
983 PageOp
->Status
= STATUS_SUCCESS
;
984 MmspCompleteAndReleasePageOp(PageOp
);
985 DPRINT("Address 0x%.8X\n", Address
);
986 return(STATUS_SUCCESS
);
990 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
992 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
994 MmUnlockSectionSegment(Segment
);
996 * Just map the desired physical page
998 Page
= Offset
>> PAGE_SHIFT
;
999 Status
= MmCreateVirtualMappingUnsafe(Process
,
1004 if (!NT_SUCCESS(Status
))
1006 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1011 * Don't add an rmap entry since the page mapped could be for
1016 MmLockPageUnsafe(Page
);
1020 * Cleanup and release locks
1022 PageOp
->Status
= STATUS_SUCCESS
;
1023 MmspCompleteAndReleasePageOp(PageOp
);
1024 DPRINT("Address 0x%.8X\n", Address
);
1025 return(STATUS_SUCCESS
);
1029 * Map anonymous memory for BSS sections
1031 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1033 MmUnlockSectionSegment(Segment
);
1034 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1035 if (!NT_SUCCESS(Status
))
1037 MmUnlockAddressSpace(AddressSpace
);
1038 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1039 MmLockAddressSpace(AddressSpace
);
1041 if (!NT_SUCCESS(Status
))
1043 KeBugCheck(MEMORY_MANAGEMENT
);
1045 Status
= MmCreateVirtualMapping(Process
,
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1053 KeBugCheck(MEMORY_MANAGEMENT
);
1056 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1063 * Cleanup and release locks
1065 PageOp
->Status
= STATUS_SUCCESS
;
1066 MmspCompleteAndReleasePageOp(PageOp
);
1067 DPRINT("Address 0x%.8X\n", Address
);
1068 return(STATUS_SUCCESS
);
1072 * Get the entry corresponding to the offset within the section
1074 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1079 * If the entry is zero (and it can't change because we have
1080 * locked the segment) then we need to load the page.
1084 * Release all our locks and read in the page from disk
1086 MmUnlockSectionSegment(Segment
);
1087 MmUnlockAddressSpace(AddressSpace
);
1089 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1090 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1092 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1093 if (!NT_SUCCESS(Status
))
1095 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1100 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1101 if (!NT_SUCCESS(Status
))
1103 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1106 if (!NT_SUCCESS(Status
))
1109 * FIXME: What do we know in this case?
1112 * Cleanup and release locks
1114 MmLockAddressSpace(AddressSpace
);
1115 PageOp
->Status
= Status
;
1116 MmspCompleteAndReleasePageOp(PageOp
);
1117 DPRINT("Address 0x%.8X\n", Address
);
1121 * Relock the address space and segment
1123 MmLockAddressSpace(AddressSpace
);
1124 MmLockSectionSegment(Segment
);
1127 * Check the entry. No one should change the status of a page
1128 * that has a pending page-in.
1130 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1131 if (Entry
!= Entry1
)
1133 DPRINT1("Someone changed ppte entry while we slept\n");
1134 KeBugCheck(MEMORY_MANAGEMENT
);
1138 * Mark the offset within the section as having valid, in-memory
1141 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1142 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1143 MmUnlockSectionSegment(Segment
);
1145 Status
= MmCreateVirtualMapping(Process
,
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT1("Unable to create virtual mapping\n");
1153 KeBugCheck(MEMORY_MANAGEMENT
);
1155 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1161 PageOp
->Status
= STATUS_SUCCESS
;
1162 MmspCompleteAndReleasePageOp(PageOp
);
1163 DPRINT("Address 0x%.8X\n", Address
);
1164 return(STATUS_SUCCESS
);
1166 else if (IS_SWAP_FROM_SSE(Entry
))
1168 SWAPENTRY SwapEntry
;
1170 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1173 * Release all our locks and read in the page from disk
1175 MmUnlockSectionSegment(Segment
);
1177 MmUnlockAddressSpace(AddressSpace
);
1179 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1180 if (!NT_SUCCESS(Status
))
1182 KeBugCheck(MEMORY_MANAGEMENT
);
1185 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1186 if (!NT_SUCCESS(Status
))
1188 KeBugCheck(MEMORY_MANAGEMENT
);
1192 * Relock the address space and segment
1194 MmLockAddressSpace(AddressSpace
);
1195 MmLockSectionSegment(Segment
);
1198 * Check the entry. No one should change the status of a page
1199 * that has a pending page-in.
1201 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1202 if (Entry
!= Entry1
)
1204 DPRINT1("Someone changed ppte entry while we slept\n");
1205 KeBugCheck(MEMORY_MANAGEMENT
);
1209 * Mark the offset within the section as having valid, in-memory
1212 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1213 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1214 MmUnlockSectionSegment(Segment
);
1217 * Save the swap entry.
1219 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1220 Status
= MmCreateVirtualMapping(Process
,
1225 if (!NT_SUCCESS(Status
))
1227 DPRINT1("Unable to create virtual mapping\n");
1228 KeBugCheck(MEMORY_MANAGEMENT
);
1230 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1235 PageOp
->Status
= STATUS_SUCCESS
;
1236 MmspCompleteAndReleasePageOp(PageOp
);
1237 DPRINT("Address 0x%.8X\n", Address
);
1238 return(STATUS_SUCCESS
);
1243 * If the section offset is already in-memory and valid then just
1244 * take another reference to the page
1247 Page
= PFN_FROM_SSE(Entry
);
1249 MmSharePageEntrySectionSegment(Segment
, Offset
);
1250 MmUnlockSectionSegment(Segment
);
1252 Status
= MmCreateVirtualMapping(Process
,
1257 if (!NT_SUCCESS(Status
))
1259 DPRINT1("Unable to create virtual mapping\n");
1260 KeBugCheck(MEMORY_MANAGEMENT
);
1262 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1267 PageOp
->Status
= STATUS_SUCCESS
;
1268 MmspCompleteAndReleasePageOp(PageOp
);
1269 DPRINT("Address 0x%.8X\n", Address
);
1270 return(STATUS_SUCCESS
);
1276 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1277 MEMORY_AREA
* MemoryArea
,
1281 PMM_SECTION_SEGMENT Segment
;
1282 PROS_SECTION_OBJECT Section
;
1291 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1293 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1296 * Check if the page has been paged out or has already been set readwrite
1298 if (!MmIsPagePresent(Process
, Address
) ||
1299 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1301 DPRINT("Address 0x%.8X\n", Address
);
1302 return(STATUS_SUCCESS
);
1306 * Find the offset of the page
1308 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1309 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1310 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1312 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1313 Section
= MemoryArea
->Data
.SectionData
.Section
;
1314 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1315 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1320 MmLockSectionSegment(Segment
);
1322 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1323 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1325 MmUnlockSectionSegment(Segment
);
1328 * Check if we are doing COW
1330 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1331 (Region
->Protect
== PAGE_READWRITE
||
1332 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1334 DPRINT("Address 0x%.8X\n", Address
);
1335 return(STATUS_ACCESS_VIOLATION
);
1338 if (IS_SWAP_FROM_SSE(Entry
) ||
1339 PFN_FROM_SSE(Entry
) != OldPage
)
1341 /* This is a private page. We must only change the page protection. */
1342 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1343 return(STATUS_SUCCESS
);
1347 * Get or create a pageop
1349 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1350 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1353 DPRINT1("MmGetPageOp failed\n");
1354 KeBugCheck(MEMORY_MANAGEMENT
);
1358 * Wait for any other operations to complete
1360 if (PageOp
->Thread
!= PsGetCurrentThread())
1362 MmUnlockAddressSpace(AddressSpace
);
1363 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1365 * Check for various strange conditions
1367 if (Status
== STATUS_TIMEOUT
)
1369 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1370 KeBugCheck(MEMORY_MANAGEMENT
);
1372 if (PageOp
->Status
== STATUS_PENDING
)
1374 DPRINT1("Woke for page op before completion\n");
1375 KeBugCheck(MEMORY_MANAGEMENT
);
1378 * Restart the operation
1380 MmLockAddressSpace(AddressSpace
);
1381 MmspCompleteAndReleasePageOp(PageOp
);
1382 DPRINT("Address 0x%.8X\n", Address
);
1383 return(STATUS_MM_RESTART_OPERATION
);
1387 * Release locks now we have the pageop
1389 MmUnlockAddressSpace(AddressSpace
);
1394 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1395 if (!NT_SUCCESS(Status
))
1397 KeBugCheck(MEMORY_MANAGEMENT
);
1403 MiCopyFromUserPage(NewPage
, PAddress
);
1405 MmLockAddressSpace(AddressSpace
);
1407 * Delete the old entry.
1409 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1412 * Set the PTE to point to the new page
1414 Status
= MmCreateVirtualMapping(Process
,
1419 if (!NT_SUCCESS(Status
))
1421 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1422 KeBugCheck(MEMORY_MANAGEMENT
);
1425 if (!NT_SUCCESS(Status
))
1427 DPRINT1("Unable to create virtual mapping\n");
1428 KeBugCheck(MEMORY_MANAGEMENT
);
1432 MmLockPage(NewPage
);
1433 MmUnlockPage(OldPage
);
1437 * Unshare the old page.
1439 MmDeleteRmap(OldPage
, Process
, PAddress
);
1440 MmInsertRmap(NewPage
, Process
, PAddress
);
1441 MmLockSectionSegment(Segment
);
1442 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1443 MmUnlockSectionSegment(Segment
);
1445 PageOp
->Status
= STATUS_SUCCESS
;
1446 MmspCompleteAndReleasePageOp(PageOp
);
1447 DPRINT("Address 0x%.8X\n", Address
);
1448 return(STATUS_SUCCESS
);
1452 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1454 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1458 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1461 MmLockAddressSpace(&Process
->Vm
);
1464 MmDeleteVirtualMapping(Process
,
1471 PageOutContext
->WasDirty
= TRUE
;
1473 if (!PageOutContext
->Private
)
1475 MmLockSectionSegment(PageOutContext
->Segment
);
1476 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1477 PageOutContext
->Segment
,
1478 PageOutContext
->Offset
,
1479 PageOutContext
->WasDirty
,
1481 MmUnlockSectionSegment(PageOutContext
->Segment
);
1485 MmUnlockAddressSpace(&Process
->Vm
);
1488 if (PageOutContext
->Private
)
1490 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1493 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1498 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1499 MEMORY_AREA
* MemoryArea
,
1504 MM_SECTION_PAGEOUT_CONTEXT Context
;
1505 SWAPENTRY SwapEntry
;
1509 PFILE_OBJECT FileObject
;
1511 BOOLEAN DirectMapped
;
1512 BOOLEAN IsImageSection
;
1513 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1515 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1518 * Get the segment and section.
1520 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1521 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1523 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1524 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1525 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1527 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1529 FileObject
= Context
.Section
->FileObject
;
1530 DirectMapped
= FALSE
;
1531 if (FileObject
!= NULL
&&
1532 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1534 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1537 * If the file system is letting us go directly to the cache and the
1538 * memory area was mapped at an offset in the file which is page aligned
1539 * then note this is a direct mapped page.
1541 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1542 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1544 DirectMapped
= TRUE
;
1550 * This should never happen since mappings of physical memory are never
1551 * placed in the rmap lists.
1553 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1555 DPRINT1("Trying to page out from physical memory section address 0x%X "
1556 "process %d\n", Address
,
1557 Process
? Process
->UniqueProcessId
: 0);
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1562 * Get the section segment entry and the physical address.
1564 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1565 if (!MmIsPagePresent(Process
, Address
))
1567 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1568 Process
? Process
->UniqueProcessId
: 0, Address
);
1569 KeBugCheck(MEMORY_MANAGEMENT
);
1571 Page
= MmGetPfnForProcess(Process
, Address
);
1572 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1575 * Prepare the context structure for the rmap delete call.
1577 Context
.WasDirty
= FALSE
;
1578 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1579 IS_SWAP_FROM_SSE(Entry
) ||
1580 PFN_FROM_SSE(Entry
) != Page
)
1582 Context
.Private
= TRUE
;
1586 Context
.Private
= FALSE
;
1590 * Take an additional reference to the page or the cache segment.
1592 if (DirectMapped
&& !Context
.Private
)
1594 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1596 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1597 KeBugCheck(MEMORY_MANAGEMENT
);
1602 MmReferencePage(Page
);
1605 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1608 * If this wasn't a private page then we should have reduced the entry to
1609 * zero by deleting all the rmaps.
1611 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1613 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1614 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1616 KeBugCheck(MEMORY_MANAGEMENT
);
1621 * If the page wasn't dirty then we can just free it as for a readonly page.
1622 * Since we unmapped all the mappings above we know it will not suddenly
1624 * If the page is from a pagefile section and has no swap entry,
1625 * we can't free the page at this point.
1627 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1628 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1630 if (Context
.Private
)
1632 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1633 Context
.WasDirty
? "dirty" : "clean", Address
);
1634 KeBugCheck(MEMORY_MANAGEMENT
);
1636 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1638 MmSetSavedSwapEntryPage(Page
, 0);
1639 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1640 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1641 PageOp
->Status
= STATUS_SUCCESS
;
1642 MmspCompleteAndReleasePageOp(PageOp
);
1643 return(STATUS_SUCCESS
);
1646 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1648 if (Context
.Private
)
1650 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1651 Context
.WasDirty
? "dirty" : "clean", Address
);
1652 KeBugCheck(MEMORY_MANAGEMENT
);
1654 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1656 MmSetSavedSwapEntryPage(Page
, 0);
1659 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1661 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1662 PageOp
->Status
= STATUS_SUCCESS
;
1663 MmspCompleteAndReleasePageOp(PageOp
);
1664 return(STATUS_SUCCESS
);
1667 else if (!Context
.Private
&& DirectMapped
)
1671 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1673 KeBugCheck(MEMORY_MANAGEMENT
);
1675 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1676 if (!NT_SUCCESS(Status
))
1678 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1681 PageOp
->Status
= STATUS_SUCCESS
;
1682 MmspCompleteAndReleasePageOp(PageOp
);
1683 return(STATUS_SUCCESS
);
1685 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1689 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1691 KeBugCheck(MEMORY_MANAGEMENT
);
1693 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1694 PageOp
->Status
= STATUS_SUCCESS
;
1695 MmspCompleteAndReleasePageOp(PageOp
);
1696 return(STATUS_SUCCESS
);
1698 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1700 MmSetSavedSwapEntryPage(Page
, 0);
1701 MmLockAddressSpace(AddressSpace
);
1702 Status
= MmCreatePageFileMapping(Process
,
1705 MmUnlockAddressSpace(AddressSpace
);
1706 if (!NT_SUCCESS(Status
))
1708 KeBugCheck(MEMORY_MANAGEMENT
);
1710 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1711 PageOp
->Status
= STATUS_SUCCESS
;
1712 MmspCompleteAndReleasePageOp(PageOp
);
1713 return(STATUS_SUCCESS
);
1717 * If necessary, allocate an entry in the paging file for this page
1721 SwapEntry
= MmAllocSwapPage();
1724 MmShowOutOfSpaceMessagePagingFile();
1725 MmLockAddressSpace(AddressSpace
);
1727 * For private pages restore the old mappings.
1729 if (Context
.Private
)
1731 Status
= MmCreateVirtualMapping(Process
,
1733 MemoryArea
->Protect
,
1736 MmSetDirtyPage(Process
, Address
);
1744 * For non-private pages if the page wasn't direct mapped then
1745 * set it back into the section segment entry so we don't loose
1746 * our copy. Otherwise it will be handled by the cache manager.
1748 Status
= MmCreateVirtualMapping(Process
,
1750 MemoryArea
->Protect
,
1753 MmSetDirtyPage(Process
, Address
);
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1760 MmUnlockAddressSpace(AddressSpace
);
1761 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1762 MmspCompleteAndReleasePageOp(PageOp
);
1763 return(STATUS_PAGEFILE_QUOTA
);
1768 * Write the page to the pagefile
1770 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1771 if (!NT_SUCCESS(Status
))
1773 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1776 * As above: undo our actions.
1777 * FIXME: Also free the swap page.
1779 MmLockAddressSpace(AddressSpace
);
1780 if (Context
.Private
)
1782 Status
= MmCreateVirtualMapping(Process
,
1784 MemoryArea
->Protect
,
1787 MmSetDirtyPage(Process
, Address
);
1794 Status
= MmCreateVirtualMapping(Process
,
1796 MemoryArea
->Protect
,
1799 MmSetDirtyPage(Process
, Address
);
1803 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1804 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1806 MmUnlockAddressSpace(AddressSpace
);
1807 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1808 MmspCompleteAndReleasePageOp(PageOp
);
1809 return(STATUS_UNSUCCESSFUL
);
1813 * Otherwise we have succeeded.
1815 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1816 MmSetSavedSwapEntryPage(Page
, 0);
1817 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1818 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1820 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1824 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1827 if (Context
.Private
)
1829 MmLockAddressSpace(AddressSpace
);
1830 Status
= MmCreatePageFileMapping(Process
,
1833 MmUnlockAddressSpace(AddressSpace
);
1834 if (!NT_SUCCESS(Status
))
1836 KeBugCheck(MEMORY_MANAGEMENT
);
1841 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1842 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1845 PageOp
->Status
= STATUS_SUCCESS
;
1846 MmspCompleteAndReleasePageOp(PageOp
);
1847 return(STATUS_SUCCESS
);
1852 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1853 PMEMORY_AREA MemoryArea
,
1858 PROS_SECTION_OBJECT Section
;
1859 PMM_SECTION_SEGMENT Segment
;
1861 SWAPENTRY SwapEntry
;
1865 PFILE_OBJECT FileObject
;
1867 BOOLEAN DirectMapped
;
1868 BOOLEAN IsImageSection
;
1869 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1871 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1873 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1874 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1877 * Get the segment and section.
1879 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1880 Section
= MemoryArea
->Data
.SectionData
.Section
;
1881 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1883 FileObject
= Section
->FileObject
;
1884 DirectMapped
= FALSE
;
1885 if (FileObject
!= NULL
&&
1886 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1888 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1891 * If the file system is letting us go directly to the cache and the
1892 * memory area was mapped at an offset in the file which is page aligned
1893 * then note this is a direct mapped page.
1895 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1896 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1898 DirectMapped
= TRUE
;
1903 * This should never happen since mappings of physical memory are never
1904 * placed in the rmap lists.
1906 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1908 DPRINT1("Trying to write back page from physical memory mapped at %X "
1909 "process %d\n", Address
,
1910 Process
? Process
->UniqueProcessId
: 0);
1911 KeBugCheck(MEMORY_MANAGEMENT
);
1915 * Get the section segment entry and the physical address.
1917 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1918 if (!MmIsPagePresent(Process
, Address
))
1920 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1921 Process
? Process
->UniqueProcessId
: 0, Address
);
1922 KeBugCheck(MEMORY_MANAGEMENT
);
1924 Page
= MmGetPfnForProcess(Process
, Address
);
1925 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1928 * Check for a private (COWed) page.
1930 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1931 IS_SWAP_FROM_SSE(Entry
) ||
1932 PFN_FROM_SSE(Entry
) != Page
)
1942 * Speculatively set all mappings of the page to clean.
1944 MmSetCleanAllRmaps(Page
);
1947 * If this page was direct mapped from the cache then the cache manager
1948 * will take care of writing it back to disk.
1950 if (DirectMapped
&& !Private
)
1952 ASSERT(SwapEntry
== 0);
1953 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1954 PageOp
->Status
= STATUS_SUCCESS
;
1955 MmspCompleteAndReleasePageOp(PageOp
);
1956 return(STATUS_SUCCESS
);
1960 * If necessary, allocate an entry in the paging file for this page
1964 SwapEntry
= MmAllocSwapPage();
1967 MmSetDirtyAllRmaps(Page
);
1968 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1969 MmspCompleteAndReleasePageOp(PageOp
);
1970 return(STATUS_PAGEFILE_QUOTA
);
1972 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1976 * Write the page to the pagefile
1978 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1979 if (!NT_SUCCESS(Status
))
1981 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1983 MmSetDirtyAllRmaps(Page
);
1984 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1985 MmspCompleteAndReleasePageOp(PageOp
);
1986 return(STATUS_UNSUCCESSFUL
);
1990 * Otherwise we have succeeded.
1992 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1993 PageOp
->Status
= STATUS_SUCCESS
;
1994 MmspCompleteAndReleasePageOp(PageOp
);
1995 return(STATUS_SUCCESS
);
1999 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2007 PMEMORY_AREA MemoryArea
;
2008 PMM_SECTION_SEGMENT Segment
;
2009 BOOLEAN DoCOW
= FALSE
;
2011 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2013 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2014 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2016 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2017 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2022 if (OldProtect
!= NewProtect
)
2024 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2026 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2027 ULONG Protect
= NewProtect
;
2030 * If we doing COW for this segment then check if the page is
2033 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2039 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2040 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2041 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2042 Page
= MmGetPfnForProcess(Process
, Address
);
2044 Protect
= PAGE_READONLY
;
2045 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2046 IS_SWAP_FROM_SSE(Entry
) ||
2047 PFN_FROM_SSE(Entry
) != Page
)
2049 Protect
= NewProtect
;
2053 if (MmIsPagePresent(Process
, Address
))
2055 MmSetPageProtect(Process
, Address
,
2064 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2065 PMEMORY_AREA MemoryArea
,
2073 ULONG_PTR MaxLength
;
2075 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2076 if (Length
> MaxLength
)
2079 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2080 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2082 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2083 Region
->Protect
!= Protect
)
2085 return STATUS_INVALID_PAGE_PROTECTION
;
2088 *OldProtect
= Region
->Protect
;
2089 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2090 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2091 BaseAddress
, Length
, Region
->Type
, Protect
,
2092 MmAlterViewAttributes
);
2098 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2100 PMEMORY_BASIC_INFORMATION Info
,
2101 PULONG ResultLength
)
2104 PVOID RegionBaseAddress
;
2105 PROS_SECTION_OBJECT Section
;
2106 PMM_SECTION_SEGMENT Segment
;
2108 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2109 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2110 Address
, &RegionBaseAddress
);
2113 return STATUS_UNSUCCESSFUL
;
2116 Section
= MemoryArea
->Data
.SectionData
.Section
;
2117 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2119 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2120 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2121 Info
->Type
= MEM_IMAGE
;
2125 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2126 Info
->Type
= MEM_MAPPED
;
2128 Info
->BaseAddress
= RegionBaseAddress
;
2129 Info
->AllocationProtect
= MemoryArea
->Protect
;
2130 Info
->RegionSize
= Region
->Length
;
2131 Info
->State
= MEM_COMMIT
;
2132 Info
->Protect
= Region
->Protect
;
2134 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2135 return(STATUS_SUCCESS
);
2140 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2145 ULONG SavedSwapEntry
;
2150 Length
= PAGE_ROUND_UP(Segment
->Length
);
2151 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2153 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2156 if (IS_SWAP_FROM_SSE(Entry
))
2158 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2162 Page
= PFN_FROM_SSE(Entry
);
2163 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2164 if (SavedSwapEntry
!= 0)
2166 MmSetSavedSwapEntryPage(Page
, 0);
2167 MmFreeSwapPage(SavedSwapEntry
);
2169 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2171 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2177 MmpDeleteSection(PVOID ObjectBody
)
2179 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2181 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2182 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2187 PMM_SECTION_SEGMENT SectionSegments
;
2190 * NOTE: Section->ImageSection can be NULL for short time
2191 * during the section creating. If we fail for some reason
2192 * until the image section is properly initialized we shouldn't
2193 * process further here.
2195 if (Section
->ImageSection
== NULL
)
2198 SectionSegments
= Section
->ImageSection
->Segments
;
2199 NrSegments
= Section
->ImageSection
->NrSegments
;
2201 for (i
= 0; i
< NrSegments
; i
++)
2203 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2205 MmLockSectionSegment(&SectionSegments
[i
]);
2207 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2208 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2212 MmpFreePageFileSegment(&SectionSegments
[i
]);
2214 MmUnlockSectionSegment(&SectionSegments
[i
]);
2221 * NOTE: Section->Segment can be NULL for short time
2222 * during the section creating.
2224 if (Section
->Segment
== NULL
)
2227 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2229 MmpFreePageFileSegment(Section
->Segment
);
2230 MmFreePageTablesSectionSegment(Section
->Segment
);
2231 ExFreePool(Section
->Segment
);
2232 Section
->Segment
= NULL
;
2236 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2239 if (Section
->FileObject
!= NULL
)
2241 CcRosDereferenceCache(Section
->FileObject
);
2242 ObDereferenceObject(Section
->FileObject
);
2243 Section
->FileObject
= NULL
;
2248 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2250 IN ACCESS_MASK GrantedAccess
,
2251 IN ULONG ProcessHandleCount
,
2252 IN ULONG SystemHandleCount
)
2254 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2255 Object
, ProcessHandleCount
);
2261 MmCreatePhysicalMemorySection(VOID
)
2263 PROS_SECTION_OBJECT PhysSection
;
2265 OBJECT_ATTRIBUTES Obj
;
2266 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2267 LARGE_INTEGER SectionSize
;
2271 * Create the section mapping physical memory
2273 SectionSize
.QuadPart
= 0xFFFFFFFF;
2274 InitializeObjectAttributes(&Obj
,
2279 Status
= MmCreateSection((PVOID
)&PhysSection
,
2283 PAGE_EXECUTE_READWRITE
,
2287 if (!NT_SUCCESS(Status
))
2289 DPRINT1("Failed to create PhysicalMemory section\n");
2290 KeBugCheck(MEMORY_MANAGEMENT
);
2292 Status
= ObInsertObject(PhysSection
,
2298 if (!NT_SUCCESS(Status
))
2300 ObDereferenceObject(PhysSection
);
2302 ObCloseHandle(Handle
, KernelMode
);
2303 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2304 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2306 return(STATUS_SUCCESS
);
2312 MmInitSectionImplementation(VOID
)
2314 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2315 UNICODE_STRING Name
;
2317 DPRINT("Creating Section Object Type\n");
2319 /* Initialize the Section object type */
2320 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2321 RtlInitUnicodeString(&Name
, L
"Section");
2322 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2323 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2324 ObjectTypeInitializer
.PoolType
= PagedPool
;
2325 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2326 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2327 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2328 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2329 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2330 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2332 return(STATUS_SUCCESS
);
2337 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2338 ACCESS_MASK DesiredAccess
,
2339 POBJECT_ATTRIBUTES ObjectAttributes
,
2340 PLARGE_INTEGER UMaximumSize
,
2341 ULONG SectionPageProtection
,
2342 ULONG AllocationAttributes
)
2344 * Create a section which is backed by the pagefile
2347 LARGE_INTEGER MaximumSize
;
2348 PROS_SECTION_OBJECT Section
;
2349 PMM_SECTION_SEGMENT Segment
;
2352 if (UMaximumSize
== NULL
)
2354 return(STATUS_UNSUCCESSFUL
);
2356 MaximumSize
= *UMaximumSize
;
2359 * Create the section
2361 Status
= ObCreateObject(ExGetPreviousMode(),
2362 MmSectionObjectType
,
2364 ExGetPreviousMode(),
2366 sizeof(ROS_SECTION_OBJECT
),
2369 (PVOID
*)(PVOID
)&Section
);
2370 if (!NT_SUCCESS(Status
))
2378 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2379 Section
->SectionPageProtection
= SectionPageProtection
;
2380 Section
->AllocationAttributes
= AllocationAttributes
;
2381 Section
->MaximumSize
= MaximumSize
;
2382 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2383 TAG_MM_SECTION_SEGMENT
);
2384 if (Segment
== NULL
)
2386 ObDereferenceObject(Section
);
2387 return(STATUS_NO_MEMORY
);
2389 Section
->Segment
= Segment
;
2390 Segment
->ReferenceCount
= 1;
2391 ExInitializeFastMutex(&Segment
->Lock
);
2392 Segment
->FileOffset
= 0;
2393 Segment
->Protection
= SectionPageProtection
;
2394 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2395 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2396 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2397 Segment
->WriteCopy
= FALSE
;
2398 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2399 Segment
->VirtualAddress
= 0;
2400 Segment
->Characteristics
= 0;
2401 *SectionObject
= Section
;
2402 return(STATUS_SUCCESS
);
2408 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2409 ACCESS_MASK DesiredAccess
,
2410 POBJECT_ATTRIBUTES ObjectAttributes
,
2411 PLARGE_INTEGER UMaximumSize
,
2412 ULONG SectionPageProtection
,
2413 ULONG AllocationAttributes
,
2416 * Create a section backed by a data file
2419 PROS_SECTION_OBJECT Section
;
2421 LARGE_INTEGER MaximumSize
;
2422 PFILE_OBJECT FileObject
;
2423 PMM_SECTION_SEGMENT Segment
;
2425 IO_STATUS_BLOCK Iosb
;
2426 LARGE_INTEGER Offset
;
2428 FILE_STANDARD_INFORMATION FileInfo
;
2431 * Create the section
2433 Status
= ObCreateObject(ExGetPreviousMode(),
2434 MmSectionObjectType
,
2436 ExGetPreviousMode(),
2438 sizeof(ROS_SECTION_OBJECT
),
2441 (PVOID
*)(PVOID
)&Section
);
2442 if (!NT_SUCCESS(Status
))
2449 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2450 Section
->SectionPageProtection
= SectionPageProtection
;
2451 Section
->AllocationAttributes
= AllocationAttributes
;
2454 * Check file access required
2456 if (SectionPageProtection
& PAGE_READWRITE
||
2457 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2459 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2463 FileAccess
= FILE_READ_DATA
;
2467 * Reference the file handle
2469 Status
= ObReferenceObjectByHandle(FileHandle
,
2472 ExGetPreviousMode(),
2473 (PVOID
*)(PVOID
)&FileObject
,
2475 if (!NT_SUCCESS(Status
))
2477 ObDereferenceObject(Section
);
2482 * FIXME: This is propably not entirely correct. We can't look into
2483 * the standard FCB header because it might not be initialized yet
2484 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2485 * standard file information is filled on first request).
2487 Status
= IoQueryFileInformation(FileObject
,
2488 FileStandardInformation
,
2489 sizeof(FILE_STANDARD_INFORMATION
),
2492 if (!NT_SUCCESS(Status
))
2494 ObDereferenceObject(Section
);
2495 ObDereferenceObject(FileObject
);
2500 * FIXME: Revise this once a locking order for file size changes is
2503 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2505 MaximumSize
= *UMaximumSize
;
2509 MaximumSize
= FileInfo
.EndOfFile
;
2510 /* Mapping zero-sized files isn't allowed. */
2511 if (MaximumSize
.QuadPart
== 0)
2513 ObDereferenceObject(Section
);
2514 ObDereferenceObject(FileObject
);
2515 return STATUS_FILE_INVALID
;
2519 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2521 Status
= IoSetInformation(FileObject
,
2522 FileAllocationInformation
,
2523 sizeof(LARGE_INTEGER
),
2525 if (!NT_SUCCESS(Status
))
2527 ObDereferenceObject(Section
);
2528 ObDereferenceObject(FileObject
);
2529 return(STATUS_SECTION_NOT_EXTENDED
);
2533 if (FileObject
->SectionObjectPointer
== NULL
||
2534 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2537 * Read a bit so caching is initiated for the file object.
2538 * This is only needed because MiReadPage currently cannot
2539 * handle non-cached streams.
2541 Offset
.QuadPart
= 0;
2542 Status
= ZwReadFile(FileHandle
,
2551 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2553 ObDereferenceObject(Section
);
2554 ObDereferenceObject(FileObject
);
2557 if (FileObject
->SectionObjectPointer
== NULL
||
2558 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2560 /* FIXME: handle this situation */
2561 ObDereferenceObject(Section
);
2562 ObDereferenceObject(FileObject
);
2563 return STATUS_INVALID_PARAMETER
;
2570 Status
= MmspWaitForFileLock(FileObject
);
2571 if (Status
!= STATUS_SUCCESS
)
2573 ObDereferenceObject(Section
);
2574 ObDereferenceObject(FileObject
);
2579 * If this file hasn't been mapped as a data file before then allocate a
2580 * section segment to describe the data file mapping
2582 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2584 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2585 TAG_MM_SECTION_SEGMENT
);
2586 if (Segment
== NULL
)
2588 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2589 ObDereferenceObject(Section
);
2590 ObDereferenceObject(FileObject
);
2591 return(STATUS_NO_MEMORY
);
2593 Section
->Segment
= Segment
;
2594 Segment
->ReferenceCount
= 1;
2595 ExInitializeFastMutex(&Segment
->Lock
);
2597 * Set the lock before assigning the segment to the file object
2599 ExAcquireFastMutex(&Segment
->Lock
);
2600 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2602 Segment
->FileOffset
= 0;
2603 Segment
->Protection
= SectionPageProtection
;
2604 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2605 Segment
->Characteristics
= 0;
2606 Segment
->WriteCopy
= FALSE
;
2607 if (AllocationAttributes
& SEC_RESERVE
)
2609 Segment
->Length
= Segment
->RawLength
= 0;
2613 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2614 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2616 Segment
->VirtualAddress
= 0;
2617 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2622 * If the file is already mapped as a data file then we may need
2626 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2628 Section
->Segment
= Segment
;
2629 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2630 MmLockSectionSegment(Segment
);
2632 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2633 !(AllocationAttributes
& SEC_RESERVE
))
2635 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2636 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2639 MmUnlockSectionSegment(Segment
);
2640 Section
->FileObject
= FileObject
;
2641 Section
->MaximumSize
= MaximumSize
;
2642 CcRosReferenceCache(FileObject
);
2643 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2644 *SectionObject
= Section
;
2645 return(STATUS_SUCCESS
);
2649 TODO: not that great (declaring loaders statically, having to declare all of
2650 them, having to keep them extern, etc.), will fix in the future
2652 extern NTSTATUS NTAPI PeFmtCreateSection
2654 IN CONST VOID
* FileHeader
,
2655 IN SIZE_T FileHeaderSize
,
2657 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2659 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2660 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2663 extern NTSTATUS NTAPI ElfFmtCreateSection
2665 IN CONST VOID
* FileHeader
,
2666 IN SIZE_T FileHeaderSize
,
2668 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2670 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2671 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2674 /* TODO: this is a standard DDK/PSDK macro */
2675 #ifndef RTL_NUMBER_OF
2676 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2679 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2690 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2692 SIZE_T SizeOfSegments
;
2693 PMM_SECTION_SEGMENT Segments
;
2695 /* TODO: check for integer overflow */
2696 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2698 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2700 TAG_MM_SECTION_SEGMENT
);
2703 RtlZeroMemory(Segments
, SizeOfSegments
);
2711 ExeFmtpReadFile(IN PVOID File
,
2712 IN PLARGE_INTEGER Offset
,
2715 OUT PVOID
* AllocBase
,
2716 OUT PULONG ReadSize
)
2719 LARGE_INTEGER FileOffset
;
2721 ULONG OffsetAdjustment
;
2726 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2730 KeBugCheck(MEMORY_MANAGEMENT
);
2733 FileOffset
= *Offset
;
2735 /* Negative/special offset: it cannot be used in this context */
2736 if(FileOffset
.u
.HighPart
< 0)
2738 KeBugCheck(MEMORY_MANAGEMENT
);
2741 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2742 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2743 FileOffset
.u
.LowPart
= AdjustOffset
;
2745 BufferSize
= Length
+ OffsetAdjustment
;
2746 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2749 * It's ok to use paged pool, because this is a temporary buffer only used in
2750 * the loading of executables. The assumption is that MmCreateSection is
2751 * always called at low IRQLs and that these buffers don't survive a brief
2752 * initialization phase
2754 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2756 TAG('M', 'm', 'X', 'r'));
2761 Status
= MmspPageRead(File
,
2768 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2769 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2770 * to initialize internal state is even worse. Our cache manager is in need of
2774 IO_STATUS_BLOCK Iosb
;
2776 Status
= ZwReadFile(File
,
2786 if(NT_SUCCESS(Status
))
2788 UsedSize
= Iosb
.Information
;
2793 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2795 Status
= STATUS_IN_PAGE_ERROR
;
2796 ASSERT(!NT_SUCCESS(Status
));
2799 if(NT_SUCCESS(Status
))
2801 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2802 *AllocBase
= Buffer
;
2803 *ReadSize
= UsedSize
- OffsetAdjustment
;
2807 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2814 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2815 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2816 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2821 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2825 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2827 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2828 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2835 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2839 MmspAssertSegmentsSorted(ImageSectionObject
);
2841 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2843 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2847 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2848 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2849 ImageSectionObject
->Segments
[i
- 1].Length
));
2857 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2861 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2863 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2864 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2872 MmspCompareSegments(const void * x
,
2875 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2876 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2879 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2880 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2884 * Ensures an image section's segments are sorted in memory
2889 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2892 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2894 MmspAssertSegmentsSorted(ImageSectionObject
);
2898 qsort(ImageSectionObject
->Segments
,
2899 ImageSectionObject
->NrSegments
,
2900 sizeof(ImageSectionObject
->Segments
[0]),
2901 MmspCompareSegments
);
2907 * Ensures an image section's segments don't overlap in memory and don't have
2908 * gaps and don't have a null size. We let them map to overlapping file regions,
2909 * though - that's not necessarily an error
2914 MmspCheckSegmentBounds
2916 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2922 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2924 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2928 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2930 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2932 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2940 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2941 * page could be OK (Windows seems to be OK with them), and larger gaps
2942 * could lead to image sections spanning several discontiguous regions
2943 * (NtMapViewOfSection could then refuse to map them, and they could
2944 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2946 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2947 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2948 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2959 * Merges and pads an image section's segments until they all are page-aligned
2960 * and have a size that is a multiple of the page size
2965 MmspPageAlignSegments
2967 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2973 BOOLEAN Initialized
;
2974 PMM_SECTION_SEGMENT EffectiveSegment
;
2976 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2978 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2982 Initialized
= FALSE
;
2984 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2986 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2989 * The first segment requires special handling
2993 ULONG_PTR VirtualAddress
;
2994 ULONG_PTR VirtualOffset
;
2996 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2998 /* Round down the virtual address to the nearest page */
2999 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3001 /* Round up the virtual size to the nearest page */
3002 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3003 EffectiveSegment
->VirtualAddress
;
3005 /* Adjust the raw address and size */
3006 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3008 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3014 * Garbage in, garbage out: unaligned base addresses make the file
3015 * offset point in curious and odd places, but that's what we were
3018 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3019 EffectiveSegment
->RawLength
+= VirtualOffset
;
3023 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3024 ULONG_PTR EndOfEffectiveSegment
;
3026 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3027 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3030 * The current segment begins exactly where the current effective
3031 * segment ended, therefore beginning a new effective segment
3033 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3036 ASSERT(LastSegment
<= i
);
3037 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3039 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3041 if (LastSegment
!= i
)
3044 * Copy the current segment. If necessary, the effective segment
3045 * will be expanded later
3047 *EffectiveSegment
= *Segment
;
3051 * Page-align the virtual size. We know for sure the virtual address
3054 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3055 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3058 * The current segment is still part of the current effective segment:
3059 * extend the effective segment to reflect this
3061 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3063 static const ULONG FlagsToProtection
[16] =
3071 PAGE_EXECUTE_READWRITE
,
3072 PAGE_EXECUTE_READWRITE
,
3077 PAGE_EXECUTE_WRITECOPY
,
3078 PAGE_EXECUTE_WRITECOPY
,
3079 PAGE_EXECUTE_WRITECOPY
,
3080 PAGE_EXECUTE_WRITECOPY
3083 unsigned ProtectionFlags
;
3086 * Extend the file size
3089 /* Unaligned segments must be contiguous within the file */
3090 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3091 EffectiveSegment
->RawLength
))
3096 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3099 * Extend the virtual size
3101 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3103 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3104 EffectiveSegment
->VirtualAddress
;
3107 * Merge the protection
3109 EffectiveSegment
->Protection
|= Segment
->Protection
;
3111 /* Clean up redundance */
3112 ProtectionFlags
= 0;
3114 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3115 ProtectionFlags
|= 1 << 0;
3117 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3118 ProtectionFlags
|= 1 << 1;
3120 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3121 ProtectionFlags
|= 1 << 2;
3123 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3124 ProtectionFlags
|= 1 << 3;
3126 ASSERT(ProtectionFlags
< 16);
3127 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3129 /* If a segment was required to be shared and cannot, fail */
3130 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3131 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3137 * We assume no holes between segments at this point
3141 KeBugCheck(MEMORY_MANAGEMENT
);
3145 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3151 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3152 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3154 LARGE_INTEGER Offset
;
3156 PVOID FileHeaderBuffer
;
3157 ULONG FileHeaderSize
;
3159 ULONG OldNrSegments
;
3164 * Read the beginning of the file (2 pages). Should be enough to contain
3165 * all (or most) of the headers
3167 Offset
.QuadPart
= 0;
3169 /* FIXME: use FileObject instead of FileHandle */
3170 Status
= ExeFmtpReadFile (FileHandle
,
3177 if (!NT_SUCCESS(Status
))
3180 if (FileHeaderSize
== 0)
3182 ExFreePool(FileHeaderBuffer
);
3183 return STATUS_UNSUCCESSFUL
;
3187 * Look for a loader that can handle this executable
3189 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3191 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3194 /* FIXME: use FileObject instead of FileHandle */
3195 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3201 ExeFmtpAllocateSegments
);
3203 if (!NT_SUCCESS(Status
))
3205 if (ImageSectionObject
->Segments
)
3207 ExFreePool(ImageSectionObject
->Segments
);
3208 ImageSectionObject
->Segments
= NULL
;
3212 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3216 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3219 * No loader handled the format
3221 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3223 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3224 ASSERT(!NT_SUCCESS(Status
));
3227 if (!NT_SUCCESS(Status
))
3230 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3235 /* FIXME? are these values platform-dependent? */
3236 if(ImageSectionObject
->StackReserve
== 0)
3237 ImageSectionObject
->StackReserve
= 0x40000;
3239 if(ImageSectionObject
->StackCommit
== 0)
3240 ImageSectionObject
->StackCommit
= 0x1000;
3242 if(ImageSectionObject
->ImageBase
== 0)
3244 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3245 ImageSectionObject
->ImageBase
= 0x10000000;
3247 ImageSectionObject
->ImageBase
= 0x00400000;
3251 * And now the fun part: fixing the segments
3254 /* Sort them by virtual address */
3255 MmspSortSegments(ImageSectionObject
, Flags
);
3257 /* Ensure they don't overlap in memory */
3258 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3259 return STATUS_INVALID_IMAGE_FORMAT
;
3261 /* Ensure they are aligned */
3262 OldNrSegments
= ImageSectionObject
->NrSegments
;
3264 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3265 return STATUS_INVALID_IMAGE_FORMAT
;
3267 /* Trim them if the alignment phase merged some of them */
3268 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3270 PMM_SECTION_SEGMENT Segments
;
3271 SIZE_T SizeOfSegments
;
3273 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3275 Segments
= ExAllocatePoolWithTag(PagedPool
,
3277 TAG_MM_SECTION_SEGMENT
);
3279 if (Segments
== NULL
)
3280 return STATUS_INSUFFICIENT_RESOURCES
;
3282 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3283 ExFreePool(ImageSectionObject
->Segments
);
3284 ImageSectionObject
->Segments
= Segments
;
3287 /* And finish their initialization */
3288 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3290 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3291 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3293 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3294 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3297 ASSERT(NT_SUCCESS(Status
));
3302 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3303 ACCESS_MASK DesiredAccess
,
3304 POBJECT_ATTRIBUTES ObjectAttributes
,
3305 PLARGE_INTEGER UMaximumSize
,
3306 ULONG SectionPageProtection
,
3307 ULONG AllocationAttributes
,
3310 PROS_SECTION_OBJECT Section
;
3312 PFILE_OBJECT FileObject
;
3313 PMM_SECTION_SEGMENT SectionSegments
;
3314 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3316 ULONG FileAccess
= 0;
3319 * Specifying a maximum size is meaningless for an image section
3321 if (UMaximumSize
!= NULL
)
3323 return(STATUS_INVALID_PARAMETER_4
);
3327 * Check file access required
3329 if (SectionPageProtection
& PAGE_READWRITE
||
3330 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3332 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3336 FileAccess
= FILE_READ_DATA
;
3340 * Reference the file handle
3342 Status
= ObReferenceObjectByHandle(FileHandle
,
3345 ExGetPreviousMode(),
3346 (PVOID
*)(PVOID
)&FileObject
,
3349 if (!NT_SUCCESS(Status
))
3355 * Create the section
3357 Status
= ObCreateObject (ExGetPreviousMode(),
3358 MmSectionObjectType
,
3360 ExGetPreviousMode(),
3362 sizeof(ROS_SECTION_OBJECT
),
3365 (PVOID
*)(PVOID
)&Section
);
3366 if (!NT_SUCCESS(Status
))
3368 ObDereferenceObject(FileObject
);
3375 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3376 Section
->SectionPageProtection
= SectionPageProtection
;
3377 Section
->AllocationAttributes
= AllocationAttributes
;
3380 * Initialized caching for this file object if previously caching
3381 * was initialized for the same on disk file
3383 Status
= CcTryToInitializeFileCache(FileObject
);
3385 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3387 NTSTATUS StatusExeFmt
;
3389 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3390 if (ImageSectionObject
== NULL
)
3392 ObDereferenceObject(FileObject
);
3393 ObDereferenceObject(Section
);
3394 return(STATUS_NO_MEMORY
);
3397 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3399 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3401 if (!NT_SUCCESS(StatusExeFmt
))
3403 if(ImageSectionObject
->Segments
!= NULL
)
3404 ExFreePool(ImageSectionObject
->Segments
);
3406 ExFreePool(ImageSectionObject
);
3407 ObDereferenceObject(Section
);
3408 ObDereferenceObject(FileObject
);
3409 return(StatusExeFmt
);
3412 Section
->ImageSection
= ImageSectionObject
;
3413 ASSERT(ImageSectionObject
->Segments
);
3418 Status
= MmspWaitForFileLock(FileObject
);
3419 if (!NT_SUCCESS(Status
))
3421 ExFreePool(ImageSectionObject
->Segments
);
3422 ExFreePool(ImageSectionObject
);
3423 ObDereferenceObject(Section
);
3424 ObDereferenceObject(FileObject
);
3428 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3429 ImageSectionObject
, NULL
))
3432 * An other thread has initialized the same image in the background
3434 ExFreePool(ImageSectionObject
->Segments
);
3435 ExFreePool(ImageSectionObject
);
3436 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3437 Section
->ImageSection
= ImageSectionObject
;
3438 SectionSegments
= ImageSectionObject
->Segments
;
3440 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3442 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3446 Status
= StatusExeFmt
;
3453 Status
= MmspWaitForFileLock(FileObject
);
3454 if (Status
!= STATUS_SUCCESS
)
3456 ObDereferenceObject(Section
);
3457 ObDereferenceObject(FileObject
);
3461 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3462 Section
->ImageSection
= ImageSectionObject
;
3463 SectionSegments
= ImageSectionObject
->Segments
;
3466 * Otherwise just reference all the section segments
3468 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3470 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3473 Status
= STATUS_SUCCESS
;
3475 Section
->FileObject
= FileObject
;
3476 CcRosReferenceCache(FileObject
);
3477 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3478 *SectionObject
= Section
;
3486 NtCreateSection (OUT PHANDLE SectionHandle
,
3487 IN ACCESS_MASK DesiredAccess
,
3488 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3489 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3490 IN ULONG SectionPageProtection OPTIONAL
,
3491 IN ULONG AllocationAttributes
,
3492 IN HANDLE FileHandle OPTIONAL
)
3494 LARGE_INTEGER SafeMaximumSize
;
3495 PVOID SectionObject
;
3496 KPROCESSOR_MODE PreviousMode
;
3497 NTSTATUS Status
= STATUS_SUCCESS
;
3499 PreviousMode
= ExGetPreviousMode();
3501 if(PreviousMode
!= KernelMode
)
3505 if (MaximumSize
!= NULL
)
3507 /* make a copy on the stack */
3508 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3509 MaximumSize
= &SafeMaximumSize
;
3511 ProbeForWriteHandle(SectionHandle
);
3513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3515 Status
= _SEH2_GetExceptionCode();
3519 if(!NT_SUCCESS(Status
))
3525 Status
= MmCreateSection(&SectionObject
,
3529 SectionPageProtection
,
3530 AllocationAttributes
,
3533 if (NT_SUCCESS(Status
))
3535 Status
= ObInsertObject ((PVOID
)SectionObject
,
3547 /**********************************************************************
3565 NtOpenSection(PHANDLE SectionHandle
,
3566 ACCESS_MASK DesiredAccess
,
3567 POBJECT_ATTRIBUTES ObjectAttributes
)
3570 KPROCESSOR_MODE PreviousMode
;
3571 NTSTATUS Status
= STATUS_SUCCESS
;
3573 PreviousMode
= ExGetPreviousMode();
3575 if(PreviousMode
!= KernelMode
)
3579 ProbeForWriteHandle(SectionHandle
);
3581 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3583 Status
= _SEH2_GetExceptionCode();
3587 if(!NT_SUCCESS(Status
))
3593 Status
= ObOpenObjectByName(ObjectAttributes
,
3594 MmSectionObjectType
,
3601 if(NT_SUCCESS(Status
))
3605 *SectionHandle
= hSection
;
3607 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3609 Status
= _SEH2_GetExceptionCode();
3618 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3619 PROS_SECTION_OBJECT Section
,
3620 PMM_SECTION_SEGMENT Segment
,
3625 ULONG AllocationType
)
3629 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3631 BoundaryAddressMultiple
.QuadPart
= 0;
3633 Status
= MmCreateMemoryArea(AddressSpace
,
3634 MEMORY_AREA_SECTION_VIEW
,
3641 BoundaryAddressMultiple
);
3642 if (!NT_SUCCESS(Status
))
3644 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3645 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3649 ObReferenceObject((PVOID
)Section
);
3651 MArea
->Data
.SectionData
.Segment
= Segment
;
3652 MArea
->Data
.SectionData
.Section
= Section
;
3653 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3654 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3655 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3656 ViewSize
, 0, Protect
);
3658 return(STATUS_SUCCESS
);
3662 /**********************************************************************
3664 * NtMapViewOfSection
3667 * Maps a view of a section into the virtual address space of a
3672 * Handle of the section.
3675 * Handle of the process.
3678 * Desired base address (or NULL) on entry;
3679 * Actual base address of the view on exit.
3682 * Number of high order address bits that must be zero.
3685 * Size in bytes of the initially committed section of
3689 * Offset in bytes from the beginning of the section
3690 * to the beginning of the view.
3693 * Desired length of map (or zero to map all) on entry
3694 * Actual length mapped on exit.
3696 * InheritDisposition
3697 * Specified how the view is to be shared with
3701 * Type of allocation for the pages.
3704 * Protection for the committed region of the view.
3712 NtMapViewOfSection(IN HANDLE SectionHandle
,
3713 IN HANDLE ProcessHandle
,
3714 IN OUT PVOID
* BaseAddress OPTIONAL
,
3715 IN ULONG_PTR ZeroBits OPTIONAL
,
3716 IN SIZE_T CommitSize
,
3717 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3718 IN OUT PSIZE_T ViewSize
,
3719 IN SECTION_INHERIT InheritDisposition
,
3720 IN ULONG AllocationType OPTIONAL
,
3723 PVOID SafeBaseAddress
;
3724 LARGE_INTEGER SafeSectionOffset
;
3725 SIZE_T SafeViewSize
;
3726 PROS_SECTION_OBJECT Section
;
3728 KPROCESSOR_MODE PreviousMode
;
3729 PMMSUPPORT AddressSpace
;
3730 NTSTATUS Status
= STATUS_SUCCESS
;
3732 ACCESS_MASK DesiredAccess
;
3735 * Check the protection
3737 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3739 return STATUS_INVALID_PARAMETER_10
;
3742 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3743 if (tmpProtect
!= PAGE_NOACCESS
&&
3744 tmpProtect
!= PAGE_READONLY
&&
3745 tmpProtect
!= PAGE_READWRITE
&&
3746 tmpProtect
!= PAGE_WRITECOPY
&&
3747 tmpProtect
!= PAGE_EXECUTE
&&
3748 tmpProtect
!= PAGE_EXECUTE_READ
&&
3749 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3750 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3752 return STATUS_INVALID_PAGE_PROTECTION
;
3755 PreviousMode
= ExGetPreviousMode();
3757 if(PreviousMode
!= KernelMode
)
3759 SafeBaseAddress
= NULL
;
3760 SafeSectionOffset
.QuadPart
= 0;
3765 if(BaseAddress
!= NULL
)
3767 ProbeForWritePointer(BaseAddress
);
3768 SafeBaseAddress
= *BaseAddress
;
3770 if(SectionOffset
!= NULL
)
3772 ProbeForWriteLargeInteger(SectionOffset
);
3773 SafeSectionOffset
= *SectionOffset
;
3775 ProbeForWriteSize_t(ViewSize
);
3776 SafeViewSize
= *ViewSize
;
3778 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3780 Status
= _SEH2_GetExceptionCode();
3784 if(!NT_SUCCESS(Status
))
3791 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3792 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3793 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3796 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3798 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3799 PROCESS_VM_OPERATION
,
3802 (PVOID
*)(PVOID
)&Process
,
3804 if (!NT_SUCCESS(Status
))
3809 AddressSpace
= &Process
->Vm
;
3811 /* Convert NT Protection Attr to Access Mask */
3812 if (Protect
== PAGE_READONLY
)
3814 DesiredAccess
= SECTION_MAP_READ
;
3816 else if (Protect
== PAGE_READWRITE
)
3818 DesiredAccess
= SECTION_MAP_WRITE
;
3820 else if (Protect
== PAGE_WRITECOPY
)
3822 DesiredAccess
= SECTION_QUERY
;
3824 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3827 DesiredAccess
= SECTION_MAP_READ
;
3830 Status
= ObReferenceObjectByHandle(SectionHandle
,
3832 MmSectionObjectType
,
3834 (PVOID
*)(PVOID
)&Section
,
3836 if (!(NT_SUCCESS(Status
)))
3838 DPRINT("ObReference failed rc=%x\n",Status
);
3839 ObDereferenceObject(Process
);
3843 Status
= MmMapViewOfSection(Section
,
3845 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3848 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3849 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3854 /* Check if this is an image for the current process */
3855 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3856 (Process
== PsGetCurrentProcess()) &&
3857 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3859 /* Notify the debugger */
3860 DbgkMapViewOfSection(Section
,
3862 SafeSectionOffset
.LowPart
,
3866 ObDereferenceObject(Section
);
3867 ObDereferenceObject(Process
);
3869 if(NT_SUCCESS(Status
))
3871 /* copy parameters back to the caller */
3874 if(BaseAddress
!= NULL
)
3876 *BaseAddress
= SafeBaseAddress
;
3878 if(SectionOffset
!= NULL
)
3880 *SectionOffset
= SafeSectionOffset
;
3882 if(ViewSize
!= NULL
)
3884 *ViewSize
= SafeViewSize
;
3887 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3889 Status
= _SEH2_GetExceptionCode();
3898 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3899 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3902 PFILE_OBJECT FileObject
;
3905 SWAPENTRY SavedSwapEntry
;
3908 PROS_SECTION_OBJECT Section
;
3909 PMM_SECTION_SEGMENT Segment
;
3910 PMMSUPPORT AddressSpace
;
3913 AddressSpace
= (PMMSUPPORT
)Context
;
3914 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3916 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3918 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3919 MemoryArea
->Data
.SectionData
.ViewOffset
;
3921 Section
= MemoryArea
->Data
.SectionData
.Section
;
3922 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3924 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3928 MmUnlockSectionSegment(Segment
);
3929 MmUnlockAddressSpace(AddressSpace
);
3931 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3932 if (Status
!= STATUS_SUCCESS
)
3934 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3935 KeBugCheck(MEMORY_MANAGEMENT
);
3938 MmLockAddressSpace(AddressSpace
);
3939 MmLockSectionSegment(Segment
);
3940 MmspCompleteAndReleasePageOp(PageOp
);
3941 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3944 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3947 * For a dirty, datafile, non-private page mark it as dirty in the
3950 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3952 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3954 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3955 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3956 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3957 ASSERT(SwapEntry
== 0);
3966 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3968 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3969 KeBugCheck(MEMORY_MANAGEMENT
);
3971 MmFreeSwapPage(SwapEntry
);
3975 if (IS_SWAP_FROM_SSE(Entry
) ||
3976 Page
!= PFN_FROM_SSE(Entry
))
3981 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3983 DPRINT1("Found a private page in a pagefile section.\n");
3984 KeBugCheck(MEMORY_MANAGEMENT
);
3987 * Just dereference private pages
3989 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3990 if (SavedSwapEntry
!= 0)
3992 MmFreeSwapPage(SavedSwapEntry
);
3993 MmSetSavedSwapEntryPage(Page
, 0);
3995 MmDeleteRmap(Page
, Process
, Address
);
3996 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4000 MmDeleteRmap(Page
, Process
, Address
);
4001 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4007 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4011 PMEMORY_AREA MemoryArea
;
4012 PROS_SECTION_OBJECT Section
;
4013 PMM_SECTION_SEGMENT Segment
;
4014 PLIST_ENTRY CurrentEntry
;
4015 PMM_REGION CurrentRegion
;
4016 PLIST_ENTRY RegionListHead
;
4018 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4020 if (MemoryArea
== NULL
)
4022 return(STATUS_UNSUCCESSFUL
);
4025 MemoryArea
->DeleteInProgress
= TRUE
;
4026 Section
= MemoryArea
->Data
.SectionData
.Section
;
4027 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4029 MmLockSectionSegment(Segment
);
4031 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4032 while (!IsListEmpty(RegionListHead
))
4034 CurrentEntry
= RemoveHeadList(RegionListHead
);
4035 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4036 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4039 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4041 Status
= MmFreeMemoryArea(AddressSpace
,
4048 Status
= MmFreeMemoryArea(AddressSpace
,
4053 MmUnlockSectionSegment(Segment
);
4054 ObDereferenceObject(Section
);
4055 return(STATUS_SUCCESS
);
4062 MmUnmapViewOfSection(PEPROCESS Process
,
4066 PMEMORY_AREA MemoryArea
;
4067 PMMSUPPORT AddressSpace
;
4068 PROS_SECTION_OBJECT Section
;
4071 PVOID ImageBaseAddress
= 0;
4073 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4074 Process
, BaseAddress
);
4078 AddressSpace
= &Process
->Vm
;
4080 MmLockAddressSpace(AddressSpace
);
4081 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4083 if (MemoryArea
== NULL
||
4084 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4085 MemoryArea
->DeleteInProgress
)
4087 MmUnlockAddressSpace(AddressSpace
);
4088 return STATUS_NOT_MAPPED_VIEW
;
4091 MemoryArea
->DeleteInProgress
= TRUE
;
4093 while (MemoryArea
->PageOpCount
)
4095 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4099 Offset
-= PAGE_SIZE
;
4100 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4101 MemoryArea
->Data
.SectionData
.Segment
,
4102 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4105 MmUnlockAddressSpace(AddressSpace
);
4106 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4107 if (Status
!= STATUS_SUCCESS
)
4109 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4110 KeBugCheck(MEMORY_MANAGEMENT
);
4112 MmLockAddressSpace(AddressSpace
);
4113 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4115 if (MemoryArea
== NULL
||
4116 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4118 MmUnlockAddressSpace(AddressSpace
);
4119 return STATUS_NOT_MAPPED_VIEW
;
4126 Section
= MemoryArea
->Data
.SectionData
.Section
;
4128 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4132 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4133 PMM_SECTION_SEGMENT SectionSegments
;
4134 PMM_SECTION_SEGMENT Segment
;
4136 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4137 ImageSectionObject
= Section
->ImageSection
;
4138 SectionSegments
= ImageSectionObject
->Segments
;
4139 NrSegments
= ImageSectionObject
->NrSegments
;
4141 /* Search for the current segment within the section segments
4142 * and calculate the image base address */
4143 for (i
= 0; i
< NrSegments
; i
++)
4145 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4147 if (Segment
== &SectionSegments
[i
])
4149 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4154 if (i
>= NrSegments
)
4156 KeBugCheck(MEMORY_MANAGEMENT
);
4159 for (i
= 0; i
< NrSegments
; i
++)
4161 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4163 PVOID SBaseAddress
= (PVOID
)
4164 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4166 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4172 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4175 MmUnlockAddressSpace(AddressSpace
);
4177 /* Notify debugger */
4178 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4180 return(STATUS_SUCCESS
);
4183 /**********************************************************************
4185 * NtUnmapViewOfSection
4200 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4204 KPROCESSOR_MODE PreviousMode
;
4207 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4208 ProcessHandle
, BaseAddress
);
4210 PreviousMode
= ExGetPreviousMode();
4212 DPRINT("Referencing process\n");
4213 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4214 PROCESS_VM_OPERATION
,
4217 (PVOID
*)(PVOID
)&Process
,
4219 if (!NT_SUCCESS(Status
))
4221 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4225 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4227 ObDereferenceObject(Process
);
4234 * Queries the information of a section object.
4236 * @param SectionHandle
4237 * Handle to the section object. It must be opened with SECTION_QUERY
4239 * @param SectionInformationClass
4240 * Index to a certain information structure. Can be either
4241 * SectionBasicInformation or SectionImageInformation. The latter
4242 * is valid only for sections that were created with the SEC_IMAGE
4244 * @param SectionInformation
4245 * Caller supplies storage for resulting information.
4247 * Size of the supplied storage.
4248 * @param ResultLength
4256 NtQuerySection(IN HANDLE SectionHandle
,
4257 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4258 OUT PVOID SectionInformation
,
4259 IN ULONG SectionInformationLength
,
4260 OUT PULONG ResultLength OPTIONAL
)
4262 PROS_SECTION_OBJECT Section
;
4263 KPROCESSOR_MODE PreviousMode
;
4264 NTSTATUS Status
= STATUS_SUCCESS
;
4267 PreviousMode
= ExGetPreviousMode();
4269 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4271 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4273 SectionInformationLength
,
4277 if(!NT_SUCCESS(Status
))
4279 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4283 Status
= ObReferenceObjectByHandle(SectionHandle
,
4285 MmSectionObjectType
,
4287 (PVOID
*)(PVOID
)&Section
,
4289 if (NT_SUCCESS(Status
))
4291 switch (SectionInformationClass
)
4293 case SectionBasicInformation
:
4295 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4299 Sbi
->Attributes
= Section
->AllocationAttributes
;
4300 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4302 Sbi
->BaseAddress
= 0;
4303 Sbi
->Size
.QuadPart
= 0;
4307 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4308 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4311 if (ResultLength
!= NULL
)
4313 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4315 Status
= STATUS_SUCCESS
;
4317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4319 Status
= _SEH2_GetExceptionCode();
4326 case SectionImageInformation
:
4328 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4332 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4333 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4335 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4336 ImageSectionObject
= Section
->ImageSection
;
4338 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4339 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4340 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4341 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4342 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4343 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4344 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4345 Sii
->Machine
= ImageSectionObject
->Machine
;
4346 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4349 if (ResultLength
!= NULL
)
4351 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4353 Status
= STATUS_SUCCESS
;
4355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4357 Status
= _SEH2_GetExceptionCode();
4365 ObDereferenceObject(Section
);
4373 * Extends size of file backed section.
4375 * @param SectionHandle
4376 * Handle to the section object. It must be opened with
4377 * SECTION_EXTEND_SIZE access.
4378 * @param NewMaximumSize
4379 * New maximum size of the section in bytes.
4383 * @todo Move the actual code to internal function MmExtendSection.
4387 NtExtendSection(IN HANDLE SectionHandle
,
4388 IN PLARGE_INTEGER NewMaximumSize
)
4390 LARGE_INTEGER SafeNewMaximumSize
;
4391 PROS_SECTION_OBJECT Section
;
4392 KPROCESSOR_MODE PreviousMode
;
4393 NTSTATUS Status
= STATUS_SUCCESS
;
4395 PreviousMode
= ExGetPreviousMode();
4397 if(PreviousMode
!= KernelMode
)
4401 /* make a copy on the stack */
4402 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4403 NewMaximumSize
= &SafeNewMaximumSize
;
4405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4407 Status
= _SEH2_GetExceptionCode();
4411 if(!NT_SUCCESS(Status
))
4417 Status
= ObReferenceObjectByHandle(SectionHandle
,
4418 SECTION_EXTEND_SIZE
,
4419 MmSectionObjectType
,
4423 if (!NT_SUCCESS(Status
))
4428 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4430 ObfDereferenceObject(Section
);
4431 return STATUS_INVALID_PARAMETER
;
4435 * - Acquire file extneding resource.
4436 * - Check if we're not resizing the section below it's actual size!
4437 * - Extend segments if needed.
4438 * - Set file information (FileAllocationInformation) to the new size.
4439 * - Release file extending resource.
4442 ObDereferenceObject(Section
);
4444 return STATUS_NOT_IMPLEMENTED
;
4448 /**********************************************************************
4450 * MmAllocateSection@4
4460 * Code taken from ntoskrnl/mm/special.c.
4465 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4470 PMMSUPPORT AddressSpace
;
4471 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4473 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4475 BoundaryAddressMultiple
.QuadPart
= 0;
4477 AddressSpace
= MmGetKernelAddressSpace();
4478 Result
= BaseAddress
;
4479 MmLockAddressSpace(AddressSpace
);
4480 Status
= MmCreateMemoryArea (AddressSpace
,
4488 BoundaryAddressMultiple
);
4489 MmUnlockAddressSpace(AddressSpace
);
4491 if (!NT_SUCCESS(Status
))
4495 DPRINT("Result %p\n",Result
);
4497 /* Create a virtual mapping for this memory area */
4498 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4500 return ((PVOID
)Result
);
4504 /**********************************************************************
4506 * MmMapViewOfSection
4509 * Maps a view of a section into the virtual address space of a
4514 * Pointer to the section object.
4517 * Pointer to the process.
4520 * Desired base address (or NULL) on entry;
4521 * Actual base address of the view on exit.
4524 * Number of high order address bits that must be zero.
4527 * Size in bytes of the initially committed section of
4531 * Offset in bytes from the beginning of the section
4532 * to the beginning of the view.
4535 * Desired length of map (or zero to map all) on entry
4536 * Actual length mapped on exit.
4538 * InheritDisposition
4539 * Specified how the view is to be shared with
4543 * Type of allocation for the pages.
4546 * Protection for the committed region of the view.
4554 MmMapViewOfSection(IN PVOID SectionObject
,
4555 IN PEPROCESS Process
,
4556 IN OUT PVOID
*BaseAddress
,
4557 IN ULONG_PTR ZeroBits
,
4558 IN SIZE_T CommitSize
,
4559 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4560 IN OUT PSIZE_T ViewSize
,
4561 IN SECTION_INHERIT InheritDisposition
,
4562 IN ULONG AllocationType
,
4565 PROS_SECTION_OBJECT Section
;
4566 PMMSUPPORT AddressSpace
;
4568 NTSTATUS Status
= STATUS_SUCCESS
;
4572 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4574 return STATUS_INVALID_PAGE_PROTECTION
;
4578 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4579 AddressSpace
= &Process
->Vm
;
4581 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4583 MmLockAddressSpace(AddressSpace
);
4585 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4589 ULONG_PTR ImageBase
;
4591 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4592 PMM_SECTION_SEGMENT SectionSegments
;
4594 ImageSectionObject
= Section
->ImageSection
;
4595 SectionSegments
= ImageSectionObject
->Segments
;
4596 NrSegments
= ImageSectionObject
->NrSegments
;
4599 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4602 ImageBase
= ImageSectionObject
->ImageBase
;
4606 for (i
= 0; i
< NrSegments
; i
++)
4608 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4610 ULONG_PTR MaxExtent
;
4611 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4612 SectionSegments
[i
].Length
;
4613 ImageSize
= max(ImageSize
, MaxExtent
);
4617 ImageSectionObject
->ImageSize
= ImageSize
;
4619 /* Check there is enough space to map the section at that point. */
4620 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4621 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4623 /* Fail if the user requested a fixed base address. */
4624 if ((*BaseAddress
) != NULL
)
4626 MmUnlockAddressSpace(AddressSpace
);
4627 return(STATUS_UNSUCCESSFUL
);
4629 /* Otherwise find a gap to map the image. */
4630 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4633 MmUnlockAddressSpace(AddressSpace
);
4634 return(STATUS_UNSUCCESSFUL
);
4638 for (i
= 0; i
< NrSegments
; i
++)
4640 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4642 PVOID SBaseAddress
= (PVOID
)
4643 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4644 MmLockSectionSegment(&SectionSegments
[i
]);
4645 Status
= MmMapViewOfSegment(AddressSpace
,
4647 &SectionSegments
[i
],
4649 SectionSegments
[i
].Length
,
4650 SectionSegments
[i
].Protection
,
4653 MmUnlockSectionSegment(&SectionSegments
[i
]);
4654 if (!NT_SUCCESS(Status
))
4656 MmUnlockAddressSpace(AddressSpace
);
4662 *BaseAddress
= (PVOID
)ImageBase
;
4666 /* check for write access */
4667 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4668 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4670 MmUnlockAddressSpace(AddressSpace
);
4671 return STATUS_SECTION_PROTECTION
;
4673 /* check for read access */
4674 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4675 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4677 MmUnlockAddressSpace(AddressSpace
);
4678 return STATUS_SECTION_PROTECTION
;
4680 /* check for execute access */
4681 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4682 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4684 MmUnlockAddressSpace(AddressSpace
);
4685 return STATUS_SECTION_PROTECTION
;
4688 if (ViewSize
== NULL
)
4690 /* Following this pointer would lead to us to the dark side */
4691 /* What to do? Bugcheck? Return status? Do the mambo? */
4692 KeBugCheck(MEMORY_MANAGEMENT
);
4695 if (SectionOffset
== NULL
)
4701 ViewOffset
= SectionOffset
->u
.LowPart
;
4704 if ((ViewOffset
% PAGE_SIZE
) != 0)
4706 MmUnlockAddressSpace(AddressSpace
);
4707 return(STATUS_MAPPED_ALIGNMENT
);
4710 if ((*ViewSize
) == 0)
4712 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4714 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4716 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4719 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4721 MmLockSectionSegment(Section
->Segment
);
4722 Status
= MmMapViewOfSegment(AddressSpace
,
4729 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4730 MmUnlockSectionSegment(Section
->Segment
);
4731 if (!NT_SUCCESS(Status
))
4733 MmUnlockAddressSpace(AddressSpace
);
4738 MmUnlockAddressSpace(AddressSpace
);
4740 return(STATUS_SUCCESS
);
4747 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4748 IN PLARGE_INTEGER NewFileSize
)
4750 /* Check whether an ImageSectionObject exists */
4751 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4753 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4757 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4759 PMM_SECTION_SEGMENT Segment
;
4761 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4764 if (Segment
->ReferenceCount
!= 0)
4766 /* Check size of file */
4767 if (SectionObjectPointer
->SharedCacheMap
)
4769 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4770 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4778 /* Something must gone wrong
4779 * how can we have a Section but no
4781 DPRINT1("ERROR: DataSectionObject without reference!\n");
4785 DPRINT("FIXME: didn't check for outstanding write probes\n");
4795 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4805 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4806 IN MMFLUSH_TYPE FlushType
)
4810 case MmFlushForDelete
:
4811 if (SectionObjectPointer
->ImageSectionObject
||
4812 SectionObjectPointer
->DataSectionObject
)
4816 CcRosSetRemoveOnClose(SectionObjectPointer
);
4818 case MmFlushForWrite
:
4828 MmForceSectionClosed (
4829 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4830 IN BOOLEAN DelayClose
)
4841 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4842 OUT PVOID
* MappedBase
,
4843 IN OUT PULONG ViewSize
)
4845 PROS_SECTION_OBJECT Section
;
4846 PMMSUPPORT AddressSpace
;
4849 DPRINT("MmMapViewInSystemSpace() called\n");
4851 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4852 AddressSpace
= MmGetKernelAddressSpace();
4854 MmLockAddressSpace(AddressSpace
);
4857 if ((*ViewSize
) == 0)
4859 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4861 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4863 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4866 MmLockSectionSegment(Section
->Segment
);
4869 Status
= MmMapViewOfSegment(AddressSpace
,
4878 MmUnlockSectionSegment(Section
->Segment
);
4879 MmUnlockAddressSpace(AddressSpace
);
4889 MmMapViewInSessionSpace (
4891 OUT PVOID
*MappedBase
,
4892 IN OUT PSIZE_T ViewSize
4896 return STATUS_NOT_IMPLEMENTED
;
4904 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4906 PMMSUPPORT AddressSpace
;
4909 DPRINT("MmUnmapViewInSystemSpace() called\n");
4911 AddressSpace
= MmGetKernelAddressSpace();
4913 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4923 MmUnmapViewInSessionSpace (
4928 return STATUS_NOT_IMPLEMENTED
;
4935 MmSetBankedSection (ULONG Unknown0
,
4943 return (STATUS_NOT_IMPLEMENTED
);
4947 /**********************************************************************
4952 * Creates a section object.
4955 * SectionObject (OUT)
4956 * Caller supplied storage for the resulting pointer
4957 * to a SECTION_OBJECT instance;
4960 * Specifies the desired access to the section can be a
4962 * STANDARD_RIGHTS_REQUIRED |
4964 * SECTION_MAP_WRITE |
4965 * SECTION_MAP_READ |
4966 * SECTION_MAP_EXECUTE
4968 * ObjectAttributes [OPTIONAL]
4969 * Initialized attributes for the object can be used
4970 * to create a named section;
4973 * Maximizes the size of the memory section. Must be
4974 * non-NULL for a page-file backed section.
4975 * If value specified for a mapped file and the file is
4976 * not large enough, file will be extended.
4978 * SectionPageProtection
4979 * Can be a combination of:
4985 * AllocationAttributes
4986 * Can be a combination of:
4991 * Handle to a file to create a section mapped to a file
4992 * instead of a memory backed section;
5003 MmCreateSection (OUT PVOID
* Section
,
5004 IN ACCESS_MASK DesiredAccess
,
5005 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5006 IN PLARGE_INTEGER MaximumSize
,
5007 IN ULONG SectionPageProtection
,
5008 IN ULONG AllocationAttributes
,
5009 IN HANDLE FileHandle OPTIONAL
,
5010 IN PFILE_OBJECT File OPTIONAL
)
5013 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5016 * Check the protection
5018 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5019 if (Protection
!= PAGE_READONLY
&&
5020 Protection
!= PAGE_READWRITE
&&
5021 Protection
!= PAGE_WRITECOPY
&&
5022 Protection
!= PAGE_EXECUTE
&&
5023 Protection
!= PAGE_EXECUTE_READ
&&
5024 Protection
!= PAGE_EXECUTE_READWRITE
&&
5025 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5027 return STATUS_INVALID_PAGE_PROTECTION
;
5030 if (AllocationAttributes
& SEC_IMAGE
)
5032 return(MmCreateImageSection(SectionObject
,
5036 SectionPageProtection
,
5037 AllocationAttributes
,
5041 if (FileHandle
!= NULL
)
5043 return(MmCreateDataFileSection(SectionObject
,
5047 SectionPageProtection
,
5048 AllocationAttributes
,
5052 return(MmCreatePageFileSection(SectionObject
,
5056 SectionPageProtection
,
5057 AllocationAttributes
));
5062 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5063 IN OUT PULONG_PTR NumberOfPages
,
5064 IN OUT PULONG_PTR UserPfnArray
)
5067 return STATUS_NOT_IMPLEMENTED
;
5072 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5073 IN ULONG_PTR NumberOfPages
,
5074 IN OUT PULONG_PTR UserPfnArray
)
5077 return STATUS_NOT_IMPLEMENTED
;
5082 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5083 IN ULONG_PTR NumberOfPages
,
5084 IN OUT PULONG_PTR UserPfnArray
)
5087 return STATUS_NOT_IMPLEMENTED
;
5092 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5093 IN OUT PULONG_PTR NumberOfPages
,
5094 IN OUT PULONG_PTR UserPfnArray
)
5097 return STATUS_NOT_IMPLEMENTED
;
5102 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5103 IN PVOID File2MappedAsFile
)
5106 return STATUS_NOT_IMPLEMENTED
;