2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
153 PROS_SECTION_OBJECT Section
;
154 PMEMORY_AREA MemoryArea
;
155 PMMSUPPORT AddressSpace
;
156 POBJECT_NAME_INFORMATION ModuleNameInformation
;
157 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
159 /* Get the MM_AVL_TABLE from EPROCESS */
160 if (Address
>= MmSystemRangeStart
)
162 AddressSpace
= MmGetKernelAddressSpace();
166 AddressSpace
= &PsGetCurrentProcess()->Vm
;
169 /* Lock address space */
170 MmLockAddressSpace(AddressSpace
);
172 /* Locate the memory area for the process by address */
173 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
175 /* Make sure it's a section view type */
176 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
178 /* Get the section pointer to the SECTION_OBJECT */
179 Section
= MemoryArea
->Data
.SectionData
.Section
;
181 /* Unlock address space */
182 MmUnlockAddressSpace(AddressSpace
);
184 /* Get the filename of the section */
185 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
187 if (NT_SUCCESS(Status
))
189 /* Init modulename */
190 RtlCreateUnicodeString(ModuleName
,
191 ModuleNameInformation
->Name
.Buffer
);
193 /* Free temp taged buffer from MmGetFileNameForSection() */
194 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
195 DPRINT("Found ModuleName %S by address %p\n",
196 ModuleName
->Buffer
,Address
);
201 /* Unlock address space */
202 MmUnlockAddressSpace(AddressSpace
);
208 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
211 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
212 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
213 * RETURNS: Status of the wait.
216 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
218 LARGE_INTEGER Timeout
;
219 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
221 Timeout
.QuadPart
= -100000000LL; // 10 sec
224 Timeout
.QuadPart
= -100000000; // 10 sec
227 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
232 * FUNCTION: Sets the page op completion event and releases the page op.
233 * ARGUMENTS: PMM_PAGEOP.
234 * RETURNS: In shorter time than it takes you to even read this
235 * description, so don't even think about geting a mug of coffee.
238 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
240 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
241 MmReleasePageOp(PageOp
);
246 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
247 * ARGUMENTS: PFILE_OBJECT to wait for.
248 * RETURNS: Status of the wait.
251 MmspWaitForFileLock(PFILE_OBJECT File
)
253 return STATUS_SUCCESS
;
254 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
259 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
262 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
264 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
266 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
268 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
276 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
278 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
280 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
281 PMM_SECTION_SEGMENT SectionSegments
;
285 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
286 NrSegments
= ImageSectionObject
->NrSegments
;
287 SectionSegments
= ImageSectionObject
->Segments
;
288 for (i
= 0; i
< NrSegments
; i
++)
290 if (SectionSegments
[i
].ReferenceCount
!= 0)
292 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
293 SectionSegments
[i
].ReferenceCount
);
294 KeBugCheck(MEMORY_MANAGEMENT
);
296 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
298 ExFreePool(ImageSectionObject
->Segments
);
299 ExFreePool(ImageSectionObject
);
300 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
302 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
304 PMM_SECTION_SEGMENT Segment
;
306 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
309 if (Segment
->ReferenceCount
!= 0)
311 DPRINT1("Data segment still referenced\n");
312 KeBugCheck(MEMORY_MANAGEMENT
);
314 MmFreePageTablesSectionSegment(Segment
);
316 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
322 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
324 ExAcquireFastMutex(&Segment
->Lock
);
329 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
331 ExReleaseFastMutex(&Segment
->Lock
);
336 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
340 PSECTION_PAGE_TABLE Table
;
341 ULONG DirectoryOffset
;
344 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
346 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
350 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
351 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
355 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
356 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
357 TAG_SECTION_PAGE_TABLE
);
360 KeBugCheck(MEMORY_MANAGEMENT
);
362 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
363 DPRINT("Table %x\n", Table
);
366 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
367 Table
->Entry
[TableOffset
] = Entry
;
373 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
376 PSECTION_PAGE_TABLE Table
;
378 ULONG DirectoryOffset
;
381 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
383 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
385 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
389 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
390 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
391 DPRINT("Table %x\n", Table
);
397 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
398 Entry
= Table
->Entry
[TableOffset
];
404 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
409 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
412 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
413 KeBugCheck(MEMORY_MANAGEMENT
);
415 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
417 DPRINT1("Maximum share count reached\n");
418 KeBugCheck(MEMORY_MANAGEMENT
);
420 if (IS_SWAP_FROM_SSE(Entry
))
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
430 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
431 PMM_SECTION_SEGMENT Segment
,
437 BOOLEAN IsDirectMapped
= FALSE
;
439 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
442 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
447 DPRINT1("Zero share count for unshare\n");
448 KeBugCheck(MEMORY_MANAGEMENT
);
450 if (IS_SWAP_FROM_SSE(Entry
))
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
456 * If we reducing the share count of this entry to zero then set the entry
457 * to zero and tell the cache the page is no longer mapped.
459 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
461 PFILE_OBJECT FileObject
;
463 SWAPENTRY SavedSwapEntry
;
465 BOOLEAN IsImageSection
;
468 FileOffset
= Offset
+ Segment
->FileOffset
;
470 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
472 Page
= PFN_FROM_SSE(Entry
);
473 FileObject
= Section
->FileObject
;
474 if (FileObject
!= NULL
&&
475 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
478 if ((FileOffset
% PAGE_SIZE
) == 0 &&
479 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
482 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
483 IsDirectMapped
= TRUE
;
484 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
488 KeBugCheck(MEMORY_MANAGEMENT
);
493 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
494 if (SavedSwapEntry
== 0)
497 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
498 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
502 * Try to page out this page and set the swap entry
503 * within the section segment. There exist no rmap entry
504 * for this page. The pager thread can't page out a
505 * page without a rmap entry.
507 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
511 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
514 MmReleasePageMemoryConsumer(MC_USER
, Page
);
520 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
521 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
529 * We hold all locks. Nobody can do something with the current
530 * process and the current segment (also not within an other process).
533 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
540 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
541 MmSetSavedSwapEntryPage(Page
, 0);
543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
547 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
548 KeBugCheck(MEMORY_MANAGEMENT
);
554 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
556 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
559 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
562 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
565 PCACHE_SEGMENT CacheSeg
;
566 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
567 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
579 MiReadPage(PMEMORY_AREA MemoryArea
,
583 * FUNCTION: Read a page for a section backed memory area.
585 * MemoryArea - Memory area to read the page for.
586 * Offset - Offset of the page to read.
587 * Page - Variable that receives a page contains the read data.
594 PCACHE_SEGMENT CacheSeg
;
595 PFILE_OBJECT FileObject
;
599 BOOLEAN IsImageSection
;
602 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
603 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
604 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
605 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
606 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
610 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
613 * If the file system is letting us go directly to the cache and the
614 * memory area was mapped at an offset in the file which is page aligned
615 * then get the related cache segment.
617 if ((FileOffset
% PAGE_SIZE
) == 0 &&
618 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
619 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
623 * Get the related cache segment; we use a lower level interface than
624 * filesystems do because it is safe for us to use an offset with a
625 * alignment less than the file system block size.
627 Status
= CcRosGetCacheSegment(Bcb
,
633 if (!NT_SUCCESS(Status
))
640 * If the cache segment isn't up to date then call the file
641 * system to read in the data.
643 Status
= ReadCacheSegment(CacheSeg
);
644 if (!NT_SUCCESS(Status
))
646 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
651 * Retrieve the page from the cache segment that we actually want.
653 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
654 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
656 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
663 ULONG CacheSegOffset
;
666 * Allocate a page, this is rather complicated by the possibility
667 * we might have to move other things out of memory
669 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
670 if (!NT_SUCCESS(Status
))
674 Status
= CcRosGetCacheSegment(Bcb
,
680 if (!NT_SUCCESS(Status
))
687 * If the cache segment isn't up to date then call the file
688 * system to read in the data.
690 Status
= ReadCacheSegment(CacheSeg
);
691 if (!NT_SUCCESS(Status
))
693 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
698 Process
= PsGetCurrentProcess();
699 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
700 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
701 Length
= RawLength
- SegOffset
;
702 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
704 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
706 else if (CacheSegOffset
>= PAGE_SIZE
)
708 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
712 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
713 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
714 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
715 Status
= CcRosGetCacheSegment(Bcb
,
716 FileOffset
+ CacheSegOffset
,
721 if (!NT_SUCCESS(Status
))
728 * If the cache segment isn't up to date then call the file
729 * system to read in the data.
731 Status
= ReadCacheSegment(CacheSeg
);
732 if (!NT_SUCCESS(Status
))
734 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
738 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
739 if (Length
< PAGE_SIZE
)
741 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
745 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
748 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
749 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
751 return(STATUS_SUCCESS
);
756 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
757 MEMORY_AREA
* MemoryArea
,
765 PROS_SECTION_OBJECT Section
;
766 PMM_SECTION_SEGMENT Segment
;
772 BOOLEAN HasSwapEntry
;
773 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
777 * There is a window between taking the page fault and locking the
778 * address space when another thread could load the page so we check
781 if (MmIsPagePresent(Process
, Address
))
785 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
786 MmLockPage(MmGetPfnForProcess(Process
, Address
));
787 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
789 return(STATUS_SUCCESS
);
792 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
793 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
794 + MemoryArea
->Data
.SectionData
.ViewOffset
;
796 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
797 Section
= MemoryArea
->Data
.SectionData
.Section
;
798 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
799 &MemoryArea
->Data
.SectionData
.RegionListHead
,
804 MmLockSectionSegment(Segment
);
807 * Check if this page needs to be mapped COW
809 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
810 (Region
->Protect
== PAGE_READWRITE
||
811 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
813 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
817 Attributes
= Region
->Protect
;
821 * Get or create a page operation descriptor
823 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
826 DPRINT1("MmGetPageOp failed\n");
827 KeBugCheck(MEMORY_MANAGEMENT
);
831 * Check if someone else is already handling this fault, if so wait
834 if (PageOp
->Thread
!= PsGetCurrentThread())
836 MmUnlockSectionSegment(Segment
);
837 MmUnlockAddressSpace(AddressSpace
);
838 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
840 * Check for various strange conditions
842 if (Status
!= STATUS_SUCCESS
)
844 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
845 KeBugCheck(MEMORY_MANAGEMENT
);
847 if (PageOp
->Status
== STATUS_PENDING
)
849 DPRINT1("Woke for page op before completion\n");
850 KeBugCheck(MEMORY_MANAGEMENT
);
852 MmLockAddressSpace(AddressSpace
);
854 * If this wasn't a pagein then restart the operation
856 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
858 MmspCompleteAndReleasePageOp(PageOp
);
859 DPRINT("Address 0x%.8X\n", Address
);
860 return(STATUS_MM_RESTART_OPERATION
);
864 * If the thread handling this fault has failed then we don't retry
866 if (!NT_SUCCESS(PageOp
->Status
))
868 Status
= PageOp
->Status
;
869 MmspCompleteAndReleasePageOp(PageOp
);
870 DPRINT("Address 0x%.8X\n", Address
);
873 MmLockSectionSegment(Segment
);
875 * If the completed fault was for another address space then set the
878 if (!MmIsPagePresent(Process
, Address
))
880 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
881 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
883 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
886 * The page was a private page in another or in our address space
888 MmUnlockSectionSegment(Segment
);
889 MmspCompleteAndReleasePageOp(PageOp
);
890 return(STATUS_MM_RESTART_OPERATION
);
893 Page
= PFN_FROM_SSE(Entry
);
895 MmSharePageEntrySectionSegment(Segment
, Offset
);
897 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
898 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
900 Status
= MmCreateVirtualMapping(Process
,
905 if (!NT_SUCCESS(Status
))
907 DPRINT1("Unable to create virtual mapping\n");
908 KeBugCheck(MEMORY_MANAGEMENT
);
910 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
914 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
916 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
918 MmUnlockSectionSegment(Segment
);
919 PageOp
->Status
= STATUS_SUCCESS
;
920 MmspCompleteAndReleasePageOp(PageOp
);
921 DPRINT("Address 0x%.8X\n", Address
);
922 return(STATUS_SUCCESS
);
925 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
929 * Must be private page we have swapped out.
936 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
938 DPRINT1("Found a swaped out private page in a pagefile section.\n");
939 KeBugCheck(MEMORY_MANAGEMENT
);
942 MmUnlockSectionSegment(Segment
);
943 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
945 MmUnlockAddressSpace(AddressSpace
);
946 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
947 if (!NT_SUCCESS(Status
))
949 KeBugCheck(MEMORY_MANAGEMENT
);
952 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
953 if (!NT_SUCCESS(Status
))
955 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
956 KeBugCheck(MEMORY_MANAGEMENT
);
958 MmLockAddressSpace(AddressSpace
);
959 Status
= MmCreateVirtualMapping(Process
,
964 if (!NT_SUCCESS(Status
))
966 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
967 KeBugCheck(MEMORY_MANAGEMENT
);
972 * Store the swap entry for later use.
974 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
977 * Add the page to the process's working set
979 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
982 * Finish the operation
986 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
988 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
990 PageOp
->Status
= STATUS_SUCCESS
;
991 MmspCompleteAndReleasePageOp(PageOp
);
992 DPRINT("Address 0x%.8X\n", Address
);
993 return(STATUS_SUCCESS
);
997 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
999 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1001 MmUnlockSectionSegment(Segment
);
1003 * Just map the desired physical page
1005 Page
= Offset
>> PAGE_SHIFT
;
1006 Status
= MmCreateVirtualMappingUnsafe(Process
,
1011 if (!NT_SUCCESS(Status
))
1013 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1014 KeBugCheck(MEMORY_MANAGEMENT
);
1018 * Don't add an rmap entry since the page mapped could be for
1023 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1025 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1029 * Cleanup and release locks
1031 PageOp
->Status
= STATUS_SUCCESS
;
1032 MmspCompleteAndReleasePageOp(PageOp
);
1033 DPRINT("Address 0x%.8X\n", Address
);
1034 return(STATUS_SUCCESS
);
1038 * Map anonymous memory for BSS sections
1040 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1042 MmUnlockSectionSegment(Segment
);
1043 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1044 if (!NT_SUCCESS(Status
))
1046 MmUnlockAddressSpace(AddressSpace
);
1047 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1048 MmLockAddressSpace(AddressSpace
);
1050 if (!NT_SUCCESS(Status
))
1052 KeBugCheck(MEMORY_MANAGEMENT
);
1054 Status
= MmCreateVirtualMapping(Process
,
1059 if (!NT_SUCCESS(Status
))
1061 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1062 KeBugCheck(MEMORY_MANAGEMENT
);
1065 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1068 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1070 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1074 * Cleanup and release locks
1076 PageOp
->Status
= STATUS_SUCCESS
;
1077 MmspCompleteAndReleasePageOp(PageOp
);
1078 DPRINT("Address 0x%.8X\n", Address
);
1079 return(STATUS_SUCCESS
);
1083 * Get the entry corresponding to the offset within the section
1085 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1090 * If the entry is zero (and it can't change because we have
1091 * locked the segment) then we need to load the page.
1095 * Release all our locks and read in the page from disk
1097 MmUnlockSectionSegment(Segment
);
1098 MmUnlockAddressSpace(AddressSpace
);
1100 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1101 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1103 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1104 if (!NT_SUCCESS(Status
))
1106 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1111 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1112 if (!NT_SUCCESS(Status
))
1114 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1117 if (!NT_SUCCESS(Status
))
1120 * FIXME: What do we know in this case?
1123 * Cleanup and release locks
1125 MmLockAddressSpace(AddressSpace
);
1126 PageOp
->Status
= Status
;
1127 MmspCompleteAndReleasePageOp(PageOp
);
1128 DPRINT("Address 0x%.8X\n", Address
);
1132 * Relock the address space and segment
1134 MmLockAddressSpace(AddressSpace
);
1135 MmLockSectionSegment(Segment
);
1138 * Check the entry. No one should change the status of a page
1139 * that has a pending page-in.
1141 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1142 if (Entry
!= Entry1
)
1144 DPRINT1("Someone changed ppte entry while we slept\n");
1145 KeBugCheck(MEMORY_MANAGEMENT
);
1149 * Mark the offset within the section as having valid, in-memory
1152 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1153 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1154 MmUnlockSectionSegment(Segment
);
1156 Status
= MmCreateVirtualMapping(Process
,
1161 if (!NT_SUCCESS(Status
))
1163 DPRINT1("Unable to create virtual mapping\n");
1164 KeBugCheck(MEMORY_MANAGEMENT
);
1166 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1170 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1172 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1174 PageOp
->Status
= STATUS_SUCCESS
;
1175 MmspCompleteAndReleasePageOp(PageOp
);
1176 DPRINT("Address 0x%.8X\n", Address
);
1177 return(STATUS_SUCCESS
);
1179 else if (IS_SWAP_FROM_SSE(Entry
))
1181 SWAPENTRY SwapEntry
;
1183 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1186 * Release all our locks and read in the page from disk
1188 MmUnlockSectionSegment(Segment
);
1190 MmUnlockAddressSpace(AddressSpace
);
1192 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1193 if (!NT_SUCCESS(Status
))
1195 KeBugCheck(MEMORY_MANAGEMENT
);
1198 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1199 if (!NT_SUCCESS(Status
))
1201 KeBugCheck(MEMORY_MANAGEMENT
);
1205 * Relock the address space and segment
1207 MmLockAddressSpace(AddressSpace
);
1208 MmLockSectionSegment(Segment
);
1211 * Check the entry. No one should change the status of a page
1212 * that has a pending page-in.
1214 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1215 if (Entry
!= Entry1
)
1217 DPRINT1("Someone changed ppte entry while we slept\n");
1218 KeBugCheck(MEMORY_MANAGEMENT
);
1222 * Mark the offset within the section as having valid, in-memory
1225 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1226 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1227 MmUnlockSectionSegment(Segment
);
1230 * Save the swap entry.
1232 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1233 Status
= MmCreateVirtualMapping(Process
,
1238 if (!NT_SUCCESS(Status
))
1240 DPRINT1("Unable to create virtual mapping\n");
1241 KeBugCheck(MEMORY_MANAGEMENT
);
1243 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1246 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1248 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1250 PageOp
->Status
= STATUS_SUCCESS
;
1251 MmspCompleteAndReleasePageOp(PageOp
);
1252 DPRINT("Address 0x%.8X\n", Address
);
1253 return(STATUS_SUCCESS
);
1258 * If the section offset is already in-memory and valid then just
1259 * take another reference to the page
1262 Page
= PFN_FROM_SSE(Entry
);
1264 MmSharePageEntrySectionSegment(Segment
, Offset
);
1265 MmUnlockSectionSegment(Segment
);
1267 Status
= MmCreateVirtualMapping(Process
,
1272 if (!NT_SUCCESS(Status
))
1274 DPRINT1("Unable to create virtual mapping\n");
1275 KeBugCheck(MEMORY_MANAGEMENT
);
1277 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1280 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1282 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1284 PageOp
->Status
= STATUS_SUCCESS
;
1285 MmspCompleteAndReleasePageOp(PageOp
);
1286 DPRINT("Address 0x%.8X\n", Address
);
1287 return(STATUS_SUCCESS
);
1293 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1294 MEMORY_AREA
* MemoryArea
,
1298 PMM_SECTION_SEGMENT Segment
;
1299 PROS_SECTION_OBJECT Section
;
1308 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1311 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1314 * Check if the page has been paged out or has already been set readwrite
1316 if (!MmIsPagePresent(Process
, Address
) ||
1317 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1319 DPRINT("Address 0x%.8X\n", Address
);
1320 return(STATUS_SUCCESS
);
1324 * Find the offset of the page
1326 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1327 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1328 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1330 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1331 Section
= MemoryArea
->Data
.SectionData
.Section
;
1332 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1333 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1338 MmLockSectionSegment(Segment
);
1340 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1341 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1343 MmUnlockSectionSegment(Segment
);
1346 * Check if we are doing COW
1348 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1349 (Region
->Protect
== PAGE_READWRITE
||
1350 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1352 DPRINT("Address 0x%.8X\n", Address
);
1353 return(STATUS_ACCESS_VIOLATION
);
1356 if (IS_SWAP_FROM_SSE(Entry
) ||
1357 PFN_FROM_SSE(Entry
) != OldPage
)
1359 /* This is a private page. We must only change the page protection. */
1360 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1361 return(STATUS_SUCCESS
);
1365 * Get or create a pageop
1367 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1368 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1371 DPRINT1("MmGetPageOp failed\n");
1372 KeBugCheck(MEMORY_MANAGEMENT
);
1376 * Wait for any other operations to complete
1378 if (PageOp
->Thread
!= PsGetCurrentThread())
1380 MmUnlockAddressSpace(AddressSpace
);
1381 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1383 * Check for various strange conditions
1385 if (Status
== STATUS_TIMEOUT
)
1387 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1388 KeBugCheck(MEMORY_MANAGEMENT
);
1390 if (PageOp
->Status
== STATUS_PENDING
)
1392 DPRINT1("Woke for page op before completion\n");
1393 KeBugCheck(MEMORY_MANAGEMENT
);
1396 * Restart the operation
1398 MmLockAddressSpace(AddressSpace
);
1399 MmspCompleteAndReleasePageOp(PageOp
);
1400 DPRINT("Address 0x%.8X\n", Address
);
1401 return(STATUS_MM_RESTART_OPERATION
);
1405 * Release locks now we have the pageop
1407 MmUnlockAddressSpace(AddressSpace
);
1412 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1413 if (!NT_SUCCESS(Status
))
1415 KeBugCheck(MEMORY_MANAGEMENT
);
1421 MiCopyFromUserPage(NewPage
, PAddress
);
1423 MmLockAddressSpace(AddressSpace
);
1425 * Delete the old entry.
1427 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1430 * Set the PTE to point to the new page
1432 Status
= MmCreateVirtualMapping(Process
,
1437 if (!NT_SUCCESS(Status
))
1439 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1440 KeBugCheck(MEMORY_MANAGEMENT
);
1443 if (!NT_SUCCESS(Status
))
1445 DPRINT1("Unable to create virtual mapping\n");
1446 KeBugCheck(MEMORY_MANAGEMENT
);
1450 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1451 MmLockPage(NewPage
);
1452 MmUnlockPage(OldPage
);
1453 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1457 * Unshare the old page.
1459 MmDeleteRmap(OldPage
, Process
, PAddress
);
1460 MmInsertRmap(NewPage
, Process
, PAddress
);
1461 MmLockSectionSegment(Segment
);
1462 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1463 MmUnlockSectionSegment(Segment
);
1465 PageOp
->Status
= STATUS_SUCCESS
;
1466 MmspCompleteAndReleasePageOp(PageOp
);
1467 DPRINT("Address 0x%.8X\n", Address
);
1468 return(STATUS_SUCCESS
);
1472 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1474 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1478 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1481 MmLockAddressSpace(&Process
->Vm
);
1484 MmDeleteVirtualMapping(Process
,
1491 PageOutContext
->WasDirty
= TRUE
;
1493 if (!PageOutContext
->Private
)
1495 MmLockSectionSegment(PageOutContext
->Segment
);
1496 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1497 PageOutContext
->Segment
,
1498 PageOutContext
->Offset
,
1499 PageOutContext
->WasDirty
,
1501 MmUnlockSectionSegment(PageOutContext
->Segment
);
1505 MmUnlockAddressSpace(&Process
->Vm
);
1508 if (PageOutContext
->Private
)
1510 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1513 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1518 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1519 MEMORY_AREA
* MemoryArea
,
1524 MM_SECTION_PAGEOUT_CONTEXT Context
;
1525 SWAPENTRY SwapEntry
;
1529 PFILE_OBJECT FileObject
;
1531 BOOLEAN DirectMapped
;
1532 BOOLEAN IsImageSection
;
1533 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1536 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1539 * Get the segment and section.
1541 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1542 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1544 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1545 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1546 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1548 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1550 FileObject
= Context
.Section
->FileObject
;
1551 DirectMapped
= FALSE
;
1552 if (FileObject
!= NULL
&&
1553 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1555 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1558 * If the file system is letting us go directly to the cache and the
1559 * memory area was mapped at an offset in the file which is page aligned
1560 * then note this is a direct mapped page.
1562 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1563 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1565 DirectMapped
= TRUE
;
1571 * This should never happen since mappings of physical memory are never
1572 * placed in the rmap lists.
1574 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1576 DPRINT1("Trying to page out from physical memory section address 0x%X "
1577 "process %d\n", Address
,
1578 Process
? Process
->UniqueProcessId
: 0);
1579 KeBugCheck(MEMORY_MANAGEMENT
);
1583 * Get the section segment entry and the physical address.
1585 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1586 if (!MmIsPagePresent(Process
, Address
))
1588 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1589 Process
? Process
->UniqueProcessId
: 0, Address
);
1590 KeBugCheck(MEMORY_MANAGEMENT
);
1592 Page
= MmGetPfnForProcess(Process
, Address
);
1593 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1596 * Prepare the context structure for the rmap delete call.
1598 Context
.WasDirty
= FALSE
;
1599 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1600 IS_SWAP_FROM_SSE(Entry
) ||
1601 PFN_FROM_SSE(Entry
) != Page
)
1603 Context
.Private
= TRUE
;
1607 Context
.Private
= FALSE
;
1611 * Take an additional reference to the page or the cache segment.
1613 if (DirectMapped
&& !Context
.Private
)
1615 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1617 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1618 KeBugCheck(MEMORY_MANAGEMENT
);
1623 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1624 MmReferencePage(Page
);
1625 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1628 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1631 * If this wasn't a private page then we should have reduced the entry to
1632 * zero by deleting all the rmaps.
1634 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1636 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1637 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1639 KeBugCheck(MEMORY_MANAGEMENT
);
1644 * If the page wasn't dirty then we can just free it as for a readonly page.
1645 * Since we unmapped all the mappings above we know it will not suddenly
1647 * If the page is from a pagefile section and has no swap entry,
1648 * we can't free the page at this point.
1650 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1651 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1653 if (Context
.Private
)
1655 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1656 Context
.WasDirty
? "dirty" : "clean", Address
);
1657 KeBugCheck(MEMORY_MANAGEMENT
);
1659 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1661 MmSetSavedSwapEntryPage(Page
, 0);
1662 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1663 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1664 PageOp
->Status
= STATUS_SUCCESS
;
1665 MmspCompleteAndReleasePageOp(PageOp
);
1666 return(STATUS_SUCCESS
);
1669 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1671 if (Context
.Private
)
1673 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1674 Context
.WasDirty
? "dirty" : "clean", Address
);
1675 KeBugCheck(MEMORY_MANAGEMENT
);
1677 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1679 MmSetSavedSwapEntryPage(Page
, 0);
1682 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1684 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1685 PageOp
->Status
= STATUS_SUCCESS
;
1686 MmspCompleteAndReleasePageOp(PageOp
);
1687 return(STATUS_SUCCESS
);
1690 else if (!Context
.Private
&& DirectMapped
)
1694 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1696 KeBugCheck(MEMORY_MANAGEMENT
);
1698 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1699 if (!NT_SUCCESS(Status
))
1701 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1702 KeBugCheck(MEMORY_MANAGEMENT
);
1704 PageOp
->Status
= STATUS_SUCCESS
;
1705 MmspCompleteAndReleasePageOp(PageOp
);
1706 return(STATUS_SUCCESS
);
1708 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1712 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1714 KeBugCheck(MEMORY_MANAGEMENT
);
1716 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1717 PageOp
->Status
= STATUS_SUCCESS
;
1718 MmspCompleteAndReleasePageOp(PageOp
);
1719 return(STATUS_SUCCESS
);
1721 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1723 MmSetSavedSwapEntryPage(Page
, 0);
1724 MmLockAddressSpace(AddressSpace
);
1725 Status
= MmCreatePageFileMapping(Process
,
1728 MmUnlockAddressSpace(AddressSpace
);
1729 if (!NT_SUCCESS(Status
))
1731 KeBugCheck(MEMORY_MANAGEMENT
);
1733 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1734 PageOp
->Status
= STATUS_SUCCESS
;
1735 MmspCompleteAndReleasePageOp(PageOp
);
1736 return(STATUS_SUCCESS
);
1740 * If necessary, allocate an entry in the paging file for this page
1744 SwapEntry
= MmAllocSwapPage();
1747 MmShowOutOfSpaceMessagePagingFile();
1748 MmLockAddressSpace(AddressSpace
);
1750 * For private pages restore the old mappings.
1752 if (Context
.Private
)
1754 Status
= MmCreateVirtualMapping(Process
,
1756 MemoryArea
->Protect
,
1759 MmSetDirtyPage(Process
, Address
);
1767 * For non-private pages if the page wasn't direct mapped then
1768 * set it back into the section segment entry so we don't loose
1769 * our copy. Otherwise it will be handled by the cache manager.
1771 Status
= MmCreateVirtualMapping(Process
,
1773 MemoryArea
->Protect
,
1776 MmSetDirtyPage(Process
, Address
);
1780 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1781 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1783 MmUnlockAddressSpace(AddressSpace
);
1784 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1785 MmspCompleteAndReleasePageOp(PageOp
);
1786 return(STATUS_PAGEFILE_QUOTA
);
1791 * Write the page to the pagefile
1793 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1794 if (!NT_SUCCESS(Status
))
1796 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1799 * As above: undo our actions.
1800 * FIXME: Also free the swap page.
1802 MmLockAddressSpace(AddressSpace
);
1803 if (Context
.Private
)
1805 Status
= MmCreateVirtualMapping(Process
,
1807 MemoryArea
->Protect
,
1810 MmSetDirtyPage(Process
, Address
);
1817 Status
= MmCreateVirtualMapping(Process
,
1819 MemoryArea
->Protect
,
1822 MmSetDirtyPage(Process
, Address
);
1826 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1827 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1829 MmUnlockAddressSpace(AddressSpace
);
1830 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1831 MmspCompleteAndReleasePageOp(PageOp
);
1832 return(STATUS_UNSUCCESSFUL
);
1836 * Otherwise we have succeeded.
1838 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1839 MmSetSavedSwapEntryPage(Page
, 0);
1840 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1841 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1843 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1847 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1850 if (Context
.Private
)
1852 MmLockAddressSpace(AddressSpace
);
1853 Status
= MmCreatePageFileMapping(Process
,
1856 MmUnlockAddressSpace(AddressSpace
);
1857 if (!NT_SUCCESS(Status
))
1859 KeBugCheck(MEMORY_MANAGEMENT
);
1864 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1865 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1868 PageOp
->Status
= STATUS_SUCCESS
;
1869 MmspCompleteAndReleasePageOp(PageOp
);
1870 return(STATUS_SUCCESS
);
1875 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1876 PMEMORY_AREA MemoryArea
,
1881 PROS_SECTION_OBJECT Section
;
1882 PMM_SECTION_SEGMENT Segment
;
1884 SWAPENTRY SwapEntry
;
1888 PFILE_OBJECT FileObject
;
1890 BOOLEAN DirectMapped
;
1891 BOOLEAN IsImageSection
;
1892 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1894 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1896 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1897 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1900 * Get the segment and section.
1902 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1903 Section
= MemoryArea
->Data
.SectionData
.Section
;
1904 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1906 FileObject
= Section
->FileObject
;
1907 DirectMapped
= FALSE
;
1908 if (FileObject
!= NULL
&&
1909 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1911 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1914 * If the file system is letting us go directly to the cache and the
1915 * memory area was mapped at an offset in the file which is page aligned
1916 * then note this is a direct mapped page.
1918 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1919 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1921 DirectMapped
= TRUE
;
1926 * This should never happen since mappings of physical memory are never
1927 * placed in the rmap lists.
1929 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1931 DPRINT1("Trying to write back page from physical memory mapped at %X "
1932 "process %d\n", Address
,
1933 Process
? Process
->UniqueProcessId
: 0);
1934 KeBugCheck(MEMORY_MANAGEMENT
);
1938 * Get the section segment entry and the physical address.
1940 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1941 if (!MmIsPagePresent(Process
, Address
))
1943 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1944 Process
? Process
->UniqueProcessId
: 0, Address
);
1945 KeBugCheck(MEMORY_MANAGEMENT
);
1947 Page
= MmGetPfnForProcess(Process
, Address
);
1948 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1951 * Check for a private (COWed) page.
1953 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1954 IS_SWAP_FROM_SSE(Entry
) ||
1955 PFN_FROM_SSE(Entry
) != Page
)
1965 * Speculatively set all mappings of the page to clean.
1967 MmSetCleanAllRmaps(Page
);
1970 * If this page was direct mapped from the cache then the cache manager
1971 * will take care of writing it back to disk.
1973 if (DirectMapped
&& !Private
)
1975 ASSERT(SwapEntry
== 0);
1976 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1977 PageOp
->Status
= STATUS_SUCCESS
;
1978 MmspCompleteAndReleasePageOp(PageOp
);
1979 return(STATUS_SUCCESS
);
1983 * If necessary, allocate an entry in the paging file for this page
1987 SwapEntry
= MmAllocSwapPage();
1990 MmSetDirtyAllRmaps(Page
);
1991 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1992 MmspCompleteAndReleasePageOp(PageOp
);
1993 return(STATUS_PAGEFILE_QUOTA
);
1995 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1999 * Write the page to the pagefile
2001 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2002 if (!NT_SUCCESS(Status
))
2004 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2006 MmSetDirtyAllRmaps(Page
);
2007 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2008 MmspCompleteAndReleasePageOp(PageOp
);
2009 return(STATUS_UNSUCCESSFUL
);
2013 * Otherwise we have succeeded.
2015 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2016 PageOp
->Status
= STATUS_SUCCESS
;
2017 MmspCompleteAndReleasePageOp(PageOp
);
2018 return(STATUS_SUCCESS
);
2022 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2030 PMEMORY_AREA MemoryArea
;
2031 PMM_SECTION_SEGMENT Segment
;
2032 BOOLEAN DoCOW
= FALSE
;
2034 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2036 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2037 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2039 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2040 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2045 if (OldProtect
!= NewProtect
)
2047 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2049 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2050 ULONG Protect
= NewProtect
;
2053 * If we doing COW for this segment then check if the page is
2056 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2062 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2063 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2064 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2065 Page
= MmGetPfnForProcess(Process
, Address
);
2067 Protect
= PAGE_READONLY
;
2068 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2069 IS_SWAP_FROM_SSE(Entry
) ||
2070 PFN_FROM_SSE(Entry
) != Page
)
2072 Protect
= NewProtect
;
2076 if (MmIsPagePresent(Process
, Address
))
2078 MmSetPageProtect(Process
, Address
,
2087 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2088 PMEMORY_AREA MemoryArea
,
2096 ULONG_PTR MaxLength
;
2098 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2099 if (Length
> MaxLength
)
2102 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2103 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2105 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2106 Region
->Protect
!= Protect
)
2108 return STATUS_INVALID_PAGE_PROTECTION
;
2111 *OldProtect
= Region
->Protect
;
2112 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2113 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2114 BaseAddress
, Length
, Region
->Type
, Protect
,
2115 MmAlterViewAttributes
);
2121 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2123 PMEMORY_BASIC_INFORMATION Info
,
2124 PULONG ResultLength
)
2127 PVOID RegionBaseAddress
;
2128 PROS_SECTION_OBJECT Section
;
2129 PMM_SECTION_SEGMENT Segment
;
2131 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2132 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2133 Address
, &RegionBaseAddress
);
2136 return STATUS_UNSUCCESSFUL
;
2139 Section
= MemoryArea
->Data
.SectionData
.Section
;
2140 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2142 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2143 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2144 Info
->Type
= MEM_IMAGE
;
2148 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2149 Info
->Type
= MEM_MAPPED
;
2151 Info
->BaseAddress
= RegionBaseAddress
;
2152 Info
->AllocationProtect
= MemoryArea
->Protect
;
2153 Info
->RegionSize
= Region
->Length
;
2154 Info
->State
= MEM_COMMIT
;
2155 Info
->Protect
= Region
->Protect
;
2157 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2158 return(STATUS_SUCCESS
);
2163 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2168 ULONG SavedSwapEntry
;
2173 Length
= PAGE_ROUND_UP(Segment
->Length
);
2174 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2176 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2179 if (IS_SWAP_FROM_SSE(Entry
))
2181 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2185 Page
= PFN_FROM_SSE(Entry
);
2186 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2187 if (SavedSwapEntry
!= 0)
2189 MmSetSavedSwapEntryPage(Page
, 0);
2190 MmFreeSwapPage(SavedSwapEntry
);
2192 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2194 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2200 MmpDeleteSection(PVOID ObjectBody
)
2202 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2204 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2205 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2210 PMM_SECTION_SEGMENT SectionSegments
;
2213 * NOTE: Section->ImageSection can be NULL for short time
2214 * during the section creating. If we fail for some reason
2215 * until the image section is properly initialized we shouldn't
2216 * process further here.
2218 if (Section
->ImageSection
== NULL
)
2221 SectionSegments
= Section
->ImageSection
->Segments
;
2222 NrSegments
= Section
->ImageSection
->NrSegments
;
2224 for (i
= 0; i
< NrSegments
; i
++)
2226 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2228 MmLockSectionSegment(&SectionSegments
[i
]);
2230 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2231 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2235 MmpFreePageFileSegment(&SectionSegments
[i
]);
2237 MmUnlockSectionSegment(&SectionSegments
[i
]);
2244 * NOTE: Section->Segment can be NULL for short time
2245 * during the section creating.
2247 if (Section
->Segment
== NULL
)
2250 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2252 MmpFreePageFileSegment(Section
->Segment
);
2253 MmFreePageTablesSectionSegment(Section
->Segment
);
2254 ExFreePool(Section
->Segment
);
2255 Section
->Segment
= NULL
;
2259 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2262 if (Section
->FileObject
!= NULL
)
2264 CcRosDereferenceCache(Section
->FileObject
);
2265 ObDereferenceObject(Section
->FileObject
);
2266 Section
->FileObject
= NULL
;
2271 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2273 IN ACCESS_MASK GrantedAccess
,
2274 IN ULONG ProcessHandleCount
,
2275 IN ULONG SystemHandleCount
)
2277 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2278 Object
, ProcessHandleCount
);
2284 MmCreatePhysicalMemorySection(VOID
)
2286 PROS_SECTION_OBJECT PhysSection
;
2288 OBJECT_ATTRIBUTES Obj
;
2289 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2290 LARGE_INTEGER SectionSize
;
2294 * Create the section mapping physical memory
2296 SectionSize
.QuadPart
= 0xFFFFFFFF;
2297 InitializeObjectAttributes(&Obj
,
2302 Status
= MmCreateSection((PVOID
)&PhysSection
,
2306 PAGE_EXECUTE_READWRITE
,
2310 if (!NT_SUCCESS(Status
))
2312 DPRINT1("Failed to create PhysicalMemory section\n");
2313 KeBugCheck(MEMORY_MANAGEMENT
);
2315 Status
= ObInsertObject(PhysSection
,
2321 if (!NT_SUCCESS(Status
))
2323 ObDereferenceObject(PhysSection
);
2325 ObCloseHandle(Handle
, KernelMode
);
2326 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2327 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2329 return(STATUS_SUCCESS
);
2335 MmInitSectionImplementation(VOID
)
2337 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2338 UNICODE_STRING Name
;
2340 DPRINT("Creating Section Object Type\n");
2342 /* Initialize the Section object type */
2343 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2344 RtlInitUnicodeString(&Name
, L
"Section");
2345 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2346 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2347 ObjectTypeInitializer
.PoolType
= PagedPool
;
2348 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2349 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2350 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2351 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2352 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2353 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2355 MmCreatePhysicalMemorySection();
2357 return(STATUS_SUCCESS
);
2362 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2363 ACCESS_MASK DesiredAccess
,
2364 POBJECT_ATTRIBUTES ObjectAttributes
,
2365 PLARGE_INTEGER UMaximumSize
,
2366 ULONG SectionPageProtection
,
2367 ULONG AllocationAttributes
)
2369 * Create a section which is backed by the pagefile
2372 LARGE_INTEGER MaximumSize
;
2373 PROS_SECTION_OBJECT Section
;
2374 PMM_SECTION_SEGMENT Segment
;
2377 if (UMaximumSize
== NULL
)
2379 return(STATUS_UNSUCCESSFUL
);
2381 MaximumSize
= *UMaximumSize
;
2384 * Create the section
2386 Status
= ObCreateObject(ExGetPreviousMode(),
2387 MmSectionObjectType
,
2389 ExGetPreviousMode(),
2391 sizeof(ROS_SECTION_OBJECT
),
2394 (PVOID
*)(PVOID
)&Section
);
2395 if (!NT_SUCCESS(Status
))
2403 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2404 Section
->SectionPageProtection
= SectionPageProtection
;
2405 Section
->AllocationAttributes
= AllocationAttributes
;
2406 Section
->MaximumSize
= MaximumSize
;
2407 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2408 TAG_MM_SECTION_SEGMENT
);
2409 if (Segment
== NULL
)
2411 ObDereferenceObject(Section
);
2412 return(STATUS_NO_MEMORY
);
2414 Section
->Segment
= Segment
;
2415 Segment
->ReferenceCount
= 1;
2416 ExInitializeFastMutex(&Segment
->Lock
);
2417 Segment
->FileOffset
= 0;
2418 Segment
->Protection
= SectionPageProtection
;
2419 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2420 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2421 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2422 Segment
->WriteCopy
= FALSE
;
2423 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2424 Segment
->VirtualAddress
= 0;
2425 Segment
->Characteristics
= 0;
2426 *SectionObject
= Section
;
2427 return(STATUS_SUCCESS
);
2433 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2434 ACCESS_MASK DesiredAccess
,
2435 POBJECT_ATTRIBUTES ObjectAttributes
,
2436 PLARGE_INTEGER UMaximumSize
,
2437 ULONG SectionPageProtection
,
2438 ULONG AllocationAttributes
,
2441 * Create a section backed by a data file
2444 PROS_SECTION_OBJECT Section
;
2446 LARGE_INTEGER MaximumSize
;
2447 PFILE_OBJECT FileObject
;
2448 PMM_SECTION_SEGMENT Segment
;
2450 IO_STATUS_BLOCK Iosb
;
2451 LARGE_INTEGER Offset
;
2453 FILE_STANDARD_INFORMATION FileInfo
;
2456 * Create the section
2458 Status
= ObCreateObject(ExGetPreviousMode(),
2459 MmSectionObjectType
,
2461 ExGetPreviousMode(),
2463 sizeof(ROS_SECTION_OBJECT
),
2466 (PVOID
*)(PVOID
)&Section
);
2467 if (!NT_SUCCESS(Status
))
2474 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2475 Section
->SectionPageProtection
= SectionPageProtection
;
2476 Section
->AllocationAttributes
= AllocationAttributes
;
2479 * Check file access required
2481 if (SectionPageProtection
& PAGE_READWRITE
||
2482 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2484 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2488 FileAccess
= FILE_READ_DATA
;
2492 * Reference the file handle
2494 Status
= ObReferenceObjectByHandle(FileHandle
,
2497 ExGetPreviousMode(),
2498 (PVOID
*)(PVOID
)&FileObject
,
2500 if (!NT_SUCCESS(Status
))
2502 ObDereferenceObject(Section
);
2507 * FIXME: This is propably not entirely correct. We can't look into
2508 * the standard FCB header because it might not be initialized yet
2509 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2510 * standard file information is filled on first request).
2512 Status
= IoQueryFileInformation(FileObject
,
2513 FileStandardInformation
,
2514 sizeof(FILE_STANDARD_INFORMATION
),
2517 if (!NT_SUCCESS(Status
))
2519 ObDereferenceObject(Section
);
2520 ObDereferenceObject(FileObject
);
2525 * FIXME: Revise this once a locking order for file size changes is
2528 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2530 MaximumSize
= *UMaximumSize
;
2534 MaximumSize
= FileInfo
.EndOfFile
;
2535 /* Mapping zero-sized files isn't allowed. */
2536 if (MaximumSize
.QuadPart
== 0)
2538 ObDereferenceObject(Section
);
2539 ObDereferenceObject(FileObject
);
2540 return STATUS_FILE_INVALID
;
2544 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2546 Status
= IoSetInformation(FileObject
,
2547 FileAllocationInformation
,
2548 sizeof(LARGE_INTEGER
),
2550 if (!NT_SUCCESS(Status
))
2552 ObDereferenceObject(Section
);
2553 ObDereferenceObject(FileObject
);
2554 return(STATUS_SECTION_NOT_EXTENDED
);
2558 if (FileObject
->SectionObjectPointer
== NULL
||
2559 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2562 * Read a bit so caching is initiated for the file object.
2563 * This is only needed because MiReadPage currently cannot
2564 * handle non-cached streams.
2566 Offset
.QuadPart
= 0;
2567 Status
= ZwReadFile(FileHandle
,
2576 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2578 ObDereferenceObject(Section
);
2579 ObDereferenceObject(FileObject
);
2582 if (FileObject
->SectionObjectPointer
== NULL
||
2583 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2585 /* FIXME: handle this situation */
2586 ObDereferenceObject(Section
);
2587 ObDereferenceObject(FileObject
);
2588 return STATUS_INVALID_PARAMETER
;
2595 Status
= MmspWaitForFileLock(FileObject
);
2596 if (Status
!= STATUS_SUCCESS
)
2598 ObDereferenceObject(Section
);
2599 ObDereferenceObject(FileObject
);
2604 * If this file hasn't been mapped as a data file before then allocate a
2605 * section segment to describe the data file mapping
2607 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2609 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2610 TAG_MM_SECTION_SEGMENT
);
2611 if (Segment
== NULL
)
2613 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2614 ObDereferenceObject(Section
);
2615 ObDereferenceObject(FileObject
);
2616 return(STATUS_NO_MEMORY
);
2618 Section
->Segment
= Segment
;
2619 Segment
->ReferenceCount
= 1;
2620 ExInitializeFastMutex(&Segment
->Lock
);
2622 * Set the lock before assigning the segment to the file object
2624 ExAcquireFastMutex(&Segment
->Lock
);
2625 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2627 Segment
->FileOffset
= 0;
2628 Segment
->Protection
= SectionPageProtection
;
2629 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2630 Segment
->Characteristics
= 0;
2631 Segment
->WriteCopy
= FALSE
;
2632 if (AllocationAttributes
& SEC_RESERVE
)
2634 Segment
->Length
= Segment
->RawLength
= 0;
2638 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2639 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2641 Segment
->VirtualAddress
= 0;
2642 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2647 * If the file is already mapped as a data file then we may need
2651 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2653 Section
->Segment
= Segment
;
2654 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2655 MmLockSectionSegment(Segment
);
2657 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2658 !(AllocationAttributes
& SEC_RESERVE
))
2660 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2661 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2664 MmUnlockSectionSegment(Segment
);
2665 Section
->FileObject
= FileObject
;
2666 Section
->MaximumSize
= MaximumSize
;
2667 CcRosReferenceCache(FileObject
);
2668 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2669 *SectionObject
= Section
;
2670 return(STATUS_SUCCESS
);
2674 TODO: not that great (declaring loaders statically, having to declare all of
2675 them, having to keep them extern, etc.), will fix in the future
2677 extern NTSTATUS NTAPI PeFmtCreateSection
2679 IN CONST VOID
* FileHeader
,
2680 IN SIZE_T FileHeaderSize
,
2682 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2684 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2685 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2688 extern NTSTATUS NTAPI ElfFmtCreateSection
2690 IN CONST VOID
* FileHeader
,
2691 IN SIZE_T FileHeaderSize
,
2693 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2695 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2696 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2699 /* TODO: this is a standard DDK/PSDK macro */
2700 #ifndef RTL_NUMBER_OF
2701 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2704 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2715 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2717 SIZE_T SizeOfSegments
;
2718 PMM_SECTION_SEGMENT Segments
;
2720 /* TODO: check for integer overflow */
2721 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2723 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2725 TAG_MM_SECTION_SEGMENT
);
2728 RtlZeroMemory(Segments
, SizeOfSegments
);
2736 ExeFmtpReadFile(IN PVOID File
,
2737 IN PLARGE_INTEGER Offset
,
2740 OUT PVOID
* AllocBase
,
2741 OUT PULONG ReadSize
)
2744 LARGE_INTEGER FileOffset
;
2746 ULONG OffsetAdjustment
;
2751 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2755 KeBugCheck(MEMORY_MANAGEMENT
);
2758 FileOffset
= *Offset
;
2760 /* Negative/special offset: it cannot be used in this context */
2761 if(FileOffset
.u
.HighPart
< 0)
2763 KeBugCheck(MEMORY_MANAGEMENT
);
2766 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2767 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2768 FileOffset
.u
.LowPart
= AdjustOffset
;
2770 BufferSize
= Length
+ OffsetAdjustment
;
2771 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2774 * It's ok to use paged pool, because this is a temporary buffer only used in
2775 * the loading of executables. The assumption is that MmCreateSection is
2776 * always called at low IRQLs and that these buffers don't survive a brief
2777 * initialization phase
2779 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2784 KeBugCheck(MEMORY_MANAGEMENT
);
2790 Status
= MmspPageRead(File
,
2797 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2798 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2799 * to initialize internal state is even worse. Our cache manager is in need of
2803 IO_STATUS_BLOCK Iosb
;
2805 Status
= ZwReadFile(File
,
2815 if(NT_SUCCESS(Status
))
2817 UsedSize
= Iosb
.Information
;
2822 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2824 Status
= STATUS_IN_PAGE_ERROR
;
2825 ASSERT(!NT_SUCCESS(Status
));
2828 if(NT_SUCCESS(Status
))
2830 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2831 *AllocBase
= Buffer
;
2832 *ReadSize
= UsedSize
- OffsetAdjustment
;
2836 ExFreePoolWithTag(Buffer
, 'rXmM');
2843 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2844 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2845 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2850 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2854 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2856 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2857 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2864 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2868 MmspAssertSegmentsSorted(ImageSectionObject
);
2870 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2872 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2876 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2877 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2878 ImageSectionObject
->Segments
[i
- 1].Length
));
2886 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2890 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2892 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2893 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2901 MmspCompareSegments(const void * x
,
2904 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2905 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2908 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2909 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2913 * Ensures an image section's segments are sorted in memory
2918 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2921 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2923 MmspAssertSegmentsSorted(ImageSectionObject
);
2927 qsort(ImageSectionObject
->Segments
,
2928 ImageSectionObject
->NrSegments
,
2929 sizeof(ImageSectionObject
->Segments
[0]),
2930 MmspCompareSegments
);
2936 * Ensures an image section's segments don't overlap in memory and don't have
2937 * gaps and don't have a null size. We let them map to overlapping file regions,
2938 * though - that's not necessarily an error
2943 MmspCheckSegmentBounds
2945 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2951 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2953 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2957 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2959 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2961 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2969 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2970 * page could be OK (Windows seems to be OK with them), and larger gaps
2971 * could lead to image sections spanning several discontiguous regions
2972 * (NtMapViewOfSection could then refuse to map them, and they could
2973 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2975 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2976 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2977 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2988 * Merges and pads an image section's segments until they all are page-aligned
2989 * and have a size that is a multiple of the page size
2994 MmspPageAlignSegments
2996 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3002 BOOLEAN Initialized
;
3003 PMM_SECTION_SEGMENT EffectiveSegment
;
3005 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3007 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3011 Initialized
= FALSE
;
3013 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3015 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3018 * The first segment requires special handling
3022 ULONG_PTR VirtualAddress
;
3023 ULONG_PTR VirtualOffset
;
3025 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3027 /* Round down the virtual address to the nearest page */
3028 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3030 /* Round up the virtual size to the nearest page */
3031 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3032 EffectiveSegment
->VirtualAddress
;
3034 /* Adjust the raw address and size */
3035 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3037 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3043 * Garbage in, garbage out: unaligned base addresses make the file
3044 * offset point in curious and odd places, but that's what we were
3047 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3048 EffectiveSegment
->RawLength
+= VirtualOffset
;
3052 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3053 ULONG_PTR EndOfEffectiveSegment
;
3055 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3056 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3059 * The current segment begins exactly where the current effective
3060 * segment ended, therefore beginning a new effective segment
3062 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3065 ASSERT(LastSegment
<= i
);
3066 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3068 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3070 if (LastSegment
!= i
)
3073 * Copy the current segment. If necessary, the effective segment
3074 * will be expanded later
3076 *EffectiveSegment
= *Segment
;
3080 * Page-align the virtual size. We know for sure the virtual address
3083 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3084 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3087 * The current segment is still part of the current effective segment:
3088 * extend the effective segment to reflect this
3090 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3092 static const ULONG FlagsToProtection
[16] =
3100 PAGE_EXECUTE_READWRITE
,
3101 PAGE_EXECUTE_READWRITE
,
3106 PAGE_EXECUTE_WRITECOPY
,
3107 PAGE_EXECUTE_WRITECOPY
,
3108 PAGE_EXECUTE_WRITECOPY
,
3109 PAGE_EXECUTE_WRITECOPY
3112 unsigned ProtectionFlags
;
3115 * Extend the file size
3118 /* Unaligned segments must be contiguous within the file */
3119 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3120 EffectiveSegment
->RawLength
))
3125 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3128 * Extend the virtual size
3130 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3132 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3133 EffectiveSegment
->VirtualAddress
;
3136 * Merge the protection
3138 EffectiveSegment
->Protection
|= Segment
->Protection
;
3140 /* Clean up redundance */
3141 ProtectionFlags
= 0;
3143 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3144 ProtectionFlags
|= 1 << 0;
3146 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3147 ProtectionFlags
|= 1 << 1;
3149 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3150 ProtectionFlags
|= 1 << 2;
3152 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3153 ProtectionFlags
|= 1 << 3;
3155 ASSERT(ProtectionFlags
< 16);
3156 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3158 /* If a segment was required to be shared and cannot, fail */
3159 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3160 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3166 * We assume no holes between segments at this point
3170 KeBugCheck(MEMORY_MANAGEMENT
);
3174 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3180 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3181 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3183 LARGE_INTEGER Offset
;
3185 PVOID FileHeaderBuffer
;
3186 ULONG FileHeaderSize
;
3188 ULONG OldNrSegments
;
3193 * Read the beginning of the file (2 pages). Should be enough to contain
3194 * all (or most) of the headers
3196 Offset
.QuadPart
= 0;
3198 /* FIXME: use FileObject instead of FileHandle */
3199 Status
= ExeFmtpReadFile (FileHandle
,
3206 if (!NT_SUCCESS(Status
))
3209 if (FileHeaderSize
== 0)
3211 ExFreePool(FileHeaderBuffer
);
3212 return STATUS_UNSUCCESSFUL
;
3216 * Look for a loader that can handle this executable
3218 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3220 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3223 /* FIXME: use FileObject instead of FileHandle */
3224 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3230 ExeFmtpAllocateSegments
);
3232 if (!NT_SUCCESS(Status
))
3234 if (ImageSectionObject
->Segments
)
3236 ExFreePool(ImageSectionObject
->Segments
);
3237 ImageSectionObject
->Segments
= NULL
;
3241 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3245 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3248 * No loader handled the format
3250 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3252 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3253 ASSERT(!NT_SUCCESS(Status
));
3256 if (!NT_SUCCESS(Status
))
3259 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3264 /* FIXME? are these values platform-dependent? */
3265 if(ImageSectionObject
->StackReserve
== 0)
3266 ImageSectionObject
->StackReserve
= 0x40000;
3268 if(ImageSectionObject
->StackCommit
== 0)
3269 ImageSectionObject
->StackCommit
= 0x1000;
3271 if(ImageSectionObject
->ImageBase
== 0)
3273 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3274 ImageSectionObject
->ImageBase
= 0x10000000;
3276 ImageSectionObject
->ImageBase
= 0x00400000;
3280 * And now the fun part: fixing the segments
3283 /* Sort them by virtual address */
3284 MmspSortSegments(ImageSectionObject
, Flags
);
3286 /* Ensure they don't overlap in memory */
3287 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3288 return STATUS_INVALID_IMAGE_FORMAT
;
3290 /* Ensure they are aligned */
3291 OldNrSegments
= ImageSectionObject
->NrSegments
;
3293 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3294 return STATUS_INVALID_IMAGE_FORMAT
;
3296 /* Trim them if the alignment phase merged some of them */
3297 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3299 PMM_SECTION_SEGMENT Segments
;
3300 SIZE_T SizeOfSegments
;
3302 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3304 Segments
= ExAllocatePoolWithTag(PagedPool
,
3306 TAG_MM_SECTION_SEGMENT
);
3308 if (Segments
== NULL
)
3309 return STATUS_INSUFFICIENT_RESOURCES
;
3311 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3312 ExFreePool(ImageSectionObject
->Segments
);
3313 ImageSectionObject
->Segments
= Segments
;
3316 /* And finish their initialization */
3317 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3319 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3320 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3322 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3323 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3326 ASSERT(NT_SUCCESS(Status
));
3331 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3332 ACCESS_MASK DesiredAccess
,
3333 POBJECT_ATTRIBUTES ObjectAttributes
,
3334 PLARGE_INTEGER UMaximumSize
,
3335 ULONG SectionPageProtection
,
3336 ULONG AllocationAttributes
,
3339 PROS_SECTION_OBJECT Section
;
3341 PFILE_OBJECT FileObject
;
3342 PMM_SECTION_SEGMENT SectionSegments
;
3343 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3345 ULONG FileAccess
= 0;
3348 * Specifying a maximum size is meaningless for an image section
3350 if (UMaximumSize
!= NULL
)
3352 return(STATUS_INVALID_PARAMETER_4
);
3356 * Check file access required
3358 if (SectionPageProtection
& PAGE_READWRITE
||
3359 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3361 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3365 FileAccess
= FILE_READ_DATA
;
3369 * Reference the file handle
3371 Status
= ObReferenceObjectByHandle(FileHandle
,
3374 ExGetPreviousMode(),
3375 (PVOID
*)(PVOID
)&FileObject
,
3378 if (!NT_SUCCESS(Status
))
3384 * Create the section
3386 Status
= ObCreateObject (ExGetPreviousMode(),
3387 MmSectionObjectType
,
3389 ExGetPreviousMode(),
3391 sizeof(ROS_SECTION_OBJECT
),
3394 (PVOID
*)(PVOID
)&Section
);
3395 if (!NT_SUCCESS(Status
))
3397 ObDereferenceObject(FileObject
);
3404 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3405 Section
->SectionPageProtection
= SectionPageProtection
;
3406 Section
->AllocationAttributes
= AllocationAttributes
;
3409 * Initialized caching for this file object if previously caching
3410 * was initialized for the same on disk file
3412 Status
= CcTryToInitializeFileCache(FileObject
);
3414 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3416 NTSTATUS StatusExeFmt
;
3418 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3419 if (ImageSectionObject
== NULL
)
3421 ObDereferenceObject(FileObject
);
3422 ObDereferenceObject(Section
);
3423 return(STATUS_NO_MEMORY
);
3426 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3428 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3430 if (!NT_SUCCESS(StatusExeFmt
))
3432 if(ImageSectionObject
->Segments
!= NULL
)
3433 ExFreePool(ImageSectionObject
->Segments
);
3435 ExFreePool(ImageSectionObject
);
3436 ObDereferenceObject(Section
);
3437 ObDereferenceObject(FileObject
);
3438 return(StatusExeFmt
);
3441 Section
->ImageSection
= ImageSectionObject
;
3442 ASSERT(ImageSectionObject
->Segments
);
3447 Status
= MmspWaitForFileLock(FileObject
);
3448 if (!NT_SUCCESS(Status
))
3450 ExFreePool(ImageSectionObject
->Segments
);
3451 ExFreePool(ImageSectionObject
);
3452 ObDereferenceObject(Section
);
3453 ObDereferenceObject(FileObject
);
3457 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3458 ImageSectionObject
, NULL
))
3461 * An other thread has initialized the same image in the background
3463 ExFreePool(ImageSectionObject
->Segments
);
3464 ExFreePool(ImageSectionObject
);
3465 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3466 Section
->ImageSection
= ImageSectionObject
;
3467 SectionSegments
= ImageSectionObject
->Segments
;
3469 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3471 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3475 Status
= StatusExeFmt
;
3482 Status
= MmspWaitForFileLock(FileObject
);
3483 if (Status
!= STATUS_SUCCESS
)
3485 ObDereferenceObject(Section
);
3486 ObDereferenceObject(FileObject
);
3490 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3491 Section
->ImageSection
= ImageSectionObject
;
3492 SectionSegments
= ImageSectionObject
->Segments
;
3495 * Otherwise just reference all the section segments
3497 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3499 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3502 Status
= STATUS_SUCCESS
;
3504 Section
->FileObject
= FileObject
;
3505 CcRosReferenceCache(FileObject
);
3506 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3507 *SectionObject
= Section
;
3515 NtCreateSection (OUT PHANDLE SectionHandle
,
3516 IN ACCESS_MASK DesiredAccess
,
3517 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3518 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3519 IN ULONG SectionPageProtection OPTIONAL
,
3520 IN ULONG AllocationAttributes
,
3521 IN HANDLE FileHandle OPTIONAL
)
3523 LARGE_INTEGER SafeMaximumSize
;
3524 PVOID SectionObject
;
3525 KPROCESSOR_MODE PreviousMode
;
3528 PreviousMode
= ExGetPreviousMode();
3530 if(PreviousMode
!= KernelMode
)
3534 if (MaximumSize
!= NULL
)
3536 /* make a copy on the stack */
3537 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3538 MaximumSize
= &SafeMaximumSize
;
3540 ProbeForWriteHandle(SectionHandle
);
3542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3544 /* Return the exception code */
3545 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3550 Status
= MmCreateSection(&SectionObject
,
3554 SectionPageProtection
,
3555 AllocationAttributes
,
3558 if (NT_SUCCESS(Status
))
3560 Status
= ObInsertObject ((PVOID
)SectionObject
,
3572 /**********************************************************************
3590 NtOpenSection(PHANDLE SectionHandle
,
3591 ACCESS_MASK DesiredAccess
,
3592 POBJECT_ATTRIBUTES ObjectAttributes
)
3595 KPROCESSOR_MODE PreviousMode
;
3598 PreviousMode
= ExGetPreviousMode();
3600 if(PreviousMode
!= KernelMode
)
3604 ProbeForWriteHandle(SectionHandle
);
3606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3608 /* Return the exception code */
3609 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3614 Status
= ObOpenObjectByName(ObjectAttributes
,
3615 MmSectionObjectType
,
3622 if(NT_SUCCESS(Status
))
3626 *SectionHandle
= hSection
;
3628 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3630 Status
= _SEH2_GetExceptionCode();
3639 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3640 PROS_SECTION_OBJECT Section
,
3641 PMM_SECTION_SEGMENT Segment
,
3646 ULONG AllocationType
)
3650 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3652 BoundaryAddressMultiple
.QuadPart
= 0;
3654 Status
= MmCreateMemoryArea(AddressSpace
,
3655 MEMORY_AREA_SECTION_VIEW
,
3662 BoundaryAddressMultiple
);
3663 if (!NT_SUCCESS(Status
))
3665 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3666 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3670 ObReferenceObject((PVOID
)Section
);
3672 MArea
->Data
.SectionData
.Segment
= Segment
;
3673 MArea
->Data
.SectionData
.Section
= Section
;
3674 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3675 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3676 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3677 ViewSize
, 0, Protect
);
3679 return(STATUS_SUCCESS
);
3683 /**********************************************************************
3685 * NtMapViewOfSection
3688 * Maps a view of a section into the virtual address space of a
3693 * Handle of the section.
3696 * Handle of the process.
3699 * Desired base address (or NULL) on entry;
3700 * Actual base address of the view on exit.
3703 * Number of high order address bits that must be zero.
3706 * Size in bytes of the initially committed section of
3710 * Offset in bytes from the beginning of the section
3711 * to the beginning of the view.
3714 * Desired length of map (or zero to map all) on entry
3715 * Actual length mapped on exit.
3717 * InheritDisposition
3718 * Specified how the view is to be shared with
3722 * Type of allocation for the pages.
3725 * Protection for the committed region of the view.
3733 NtMapViewOfSection(IN HANDLE SectionHandle
,
3734 IN HANDLE ProcessHandle
,
3735 IN OUT PVOID
* BaseAddress OPTIONAL
,
3736 IN ULONG_PTR ZeroBits OPTIONAL
,
3737 IN SIZE_T CommitSize
,
3738 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3739 IN OUT PSIZE_T ViewSize
,
3740 IN SECTION_INHERIT InheritDisposition
,
3741 IN ULONG AllocationType OPTIONAL
,
3744 PVOID SafeBaseAddress
;
3745 LARGE_INTEGER SafeSectionOffset
;
3746 SIZE_T SafeViewSize
;
3747 PROS_SECTION_OBJECT Section
;
3749 KPROCESSOR_MODE PreviousMode
;
3750 PMMSUPPORT AddressSpace
;
3753 ACCESS_MASK DesiredAccess
;
3756 * Check the protection
3758 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3760 return STATUS_INVALID_PARAMETER_10
;
3763 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3764 if (tmpProtect
!= PAGE_NOACCESS
&&
3765 tmpProtect
!= PAGE_READONLY
&&
3766 tmpProtect
!= PAGE_READWRITE
&&
3767 tmpProtect
!= PAGE_WRITECOPY
&&
3768 tmpProtect
!= PAGE_EXECUTE
&&
3769 tmpProtect
!= PAGE_EXECUTE_READ
&&
3770 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3771 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3773 return STATUS_INVALID_PAGE_PROTECTION
;
3776 PreviousMode
= ExGetPreviousMode();
3778 if(PreviousMode
!= KernelMode
)
3780 SafeBaseAddress
= NULL
;
3781 SafeSectionOffset
.QuadPart
= 0;
3786 if(BaseAddress
!= NULL
)
3788 ProbeForWritePointer(BaseAddress
);
3789 SafeBaseAddress
= *BaseAddress
;
3791 if(SectionOffset
!= NULL
)
3793 ProbeForWriteLargeInteger(SectionOffset
);
3794 SafeSectionOffset
= *SectionOffset
;
3796 ProbeForWriteSize_t(ViewSize
);
3797 SafeViewSize
= *ViewSize
;
3799 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3801 /* Return the exception code */
3802 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3808 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3809 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3810 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3813 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3815 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3816 PROCESS_VM_OPERATION
,
3819 (PVOID
*)(PVOID
)&Process
,
3821 if (!NT_SUCCESS(Status
))
3826 AddressSpace
= &Process
->Vm
;
3828 /* Convert NT Protection Attr to Access Mask */
3829 if (Protect
== PAGE_READONLY
)
3831 DesiredAccess
= SECTION_MAP_READ
;
3833 else if (Protect
== PAGE_READWRITE
)
3835 DesiredAccess
= SECTION_MAP_WRITE
;
3837 else if (Protect
== PAGE_WRITECOPY
)
3839 DesiredAccess
= SECTION_QUERY
;
3841 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3844 DesiredAccess
= SECTION_MAP_READ
;
3847 Status
= ObReferenceObjectByHandle(SectionHandle
,
3849 MmSectionObjectType
,
3851 (PVOID
*)(PVOID
)&Section
,
3853 if (!(NT_SUCCESS(Status
)))
3855 DPRINT("ObReference failed rc=%x\n",Status
);
3856 ObDereferenceObject(Process
);
3860 Status
= MmMapViewOfSection(Section
,
3862 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3865 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3866 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3871 /* Check if this is an image for the current process */
3872 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3873 (Process
== PsGetCurrentProcess()) &&
3874 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3876 /* Notify the debugger */
3877 DbgkMapViewOfSection(Section
,
3879 SafeSectionOffset
.LowPart
,
3883 ObDereferenceObject(Section
);
3884 ObDereferenceObject(Process
);
3886 if(NT_SUCCESS(Status
))
3888 /* copy parameters back to the caller */
3891 if(BaseAddress
!= NULL
)
3893 *BaseAddress
= SafeBaseAddress
;
3895 if(SectionOffset
!= NULL
)
3897 *SectionOffset
= SafeSectionOffset
;
3899 if(ViewSize
!= NULL
)
3901 *ViewSize
= SafeViewSize
;
3904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3906 Status
= _SEH2_GetExceptionCode();
3915 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3916 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3919 PFILE_OBJECT FileObject
;
3922 SWAPENTRY SavedSwapEntry
;
3925 PROS_SECTION_OBJECT Section
;
3926 PMM_SECTION_SEGMENT Segment
;
3927 PMMSUPPORT AddressSpace
;
3930 AddressSpace
= (PMMSUPPORT
)Context
;
3931 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3933 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3935 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3936 MemoryArea
->Data
.SectionData
.ViewOffset
;
3938 Section
= MemoryArea
->Data
.SectionData
.Section
;
3939 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3941 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3945 MmUnlockSectionSegment(Segment
);
3946 MmUnlockAddressSpace(AddressSpace
);
3948 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3949 if (Status
!= STATUS_SUCCESS
)
3951 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3952 KeBugCheck(MEMORY_MANAGEMENT
);
3955 MmLockAddressSpace(AddressSpace
);
3956 MmLockSectionSegment(Segment
);
3957 MmspCompleteAndReleasePageOp(PageOp
);
3958 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3961 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3964 * For a dirty, datafile, non-private page mark it as dirty in the
3967 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3969 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3971 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3972 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3973 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3974 ASSERT(SwapEntry
== 0);
3983 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3985 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3986 KeBugCheck(MEMORY_MANAGEMENT
);
3988 MmFreeSwapPage(SwapEntry
);
3992 if (IS_SWAP_FROM_SSE(Entry
) ||
3993 Page
!= PFN_FROM_SSE(Entry
))
3998 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4000 DPRINT1("Found a private page in a pagefile section.\n");
4001 KeBugCheck(MEMORY_MANAGEMENT
);
4004 * Just dereference private pages
4006 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4007 if (SavedSwapEntry
!= 0)
4009 MmFreeSwapPage(SavedSwapEntry
);
4010 MmSetSavedSwapEntryPage(Page
, 0);
4012 MmDeleteRmap(Page
, Process
, Address
);
4013 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4017 MmDeleteRmap(Page
, Process
, Address
);
4018 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4024 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4028 PMEMORY_AREA MemoryArea
;
4029 PROS_SECTION_OBJECT Section
;
4030 PMM_SECTION_SEGMENT Segment
;
4031 PLIST_ENTRY CurrentEntry
;
4032 PMM_REGION CurrentRegion
;
4033 PLIST_ENTRY RegionListHead
;
4035 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4037 if (MemoryArea
== NULL
)
4039 return(STATUS_UNSUCCESSFUL
);
4042 MemoryArea
->DeleteInProgress
= TRUE
;
4043 Section
= MemoryArea
->Data
.SectionData
.Section
;
4044 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4046 MmLockSectionSegment(Segment
);
4048 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4049 while (!IsListEmpty(RegionListHead
))
4051 CurrentEntry
= RemoveHeadList(RegionListHead
);
4052 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4053 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4056 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4058 Status
= MmFreeMemoryArea(AddressSpace
,
4065 Status
= MmFreeMemoryArea(AddressSpace
,
4070 MmUnlockSectionSegment(Segment
);
4071 ObDereferenceObject(Section
);
4072 return(STATUS_SUCCESS
);
4079 MmUnmapViewOfSection(PEPROCESS Process
,
4083 PMEMORY_AREA MemoryArea
;
4084 PMMSUPPORT AddressSpace
;
4085 PROS_SECTION_OBJECT Section
;
4088 PVOID ImageBaseAddress
= 0;
4090 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4091 Process
, BaseAddress
);
4095 AddressSpace
= &Process
->Vm
;
4097 MmLockAddressSpace(AddressSpace
);
4098 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4100 if (MemoryArea
== NULL
||
4101 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4102 MemoryArea
->DeleteInProgress
)
4104 MmUnlockAddressSpace(AddressSpace
);
4105 return STATUS_NOT_MAPPED_VIEW
;
4108 MemoryArea
->DeleteInProgress
= TRUE
;
4110 while (MemoryArea
->PageOpCount
)
4112 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4116 Offset
-= PAGE_SIZE
;
4117 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4118 MemoryArea
->Data
.SectionData
.Segment
,
4119 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4122 MmUnlockAddressSpace(AddressSpace
);
4123 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4124 if (Status
!= STATUS_SUCCESS
)
4126 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4127 KeBugCheck(MEMORY_MANAGEMENT
);
4129 MmLockAddressSpace(AddressSpace
);
4130 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4132 if (MemoryArea
== NULL
||
4133 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4135 MmUnlockAddressSpace(AddressSpace
);
4136 return STATUS_NOT_MAPPED_VIEW
;
4143 Section
= MemoryArea
->Data
.SectionData
.Section
;
4145 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4149 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4150 PMM_SECTION_SEGMENT SectionSegments
;
4151 PMM_SECTION_SEGMENT Segment
;
4153 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4154 ImageSectionObject
= Section
->ImageSection
;
4155 SectionSegments
= ImageSectionObject
->Segments
;
4156 NrSegments
= ImageSectionObject
->NrSegments
;
4158 /* Search for the current segment within the section segments
4159 * and calculate the image base address */
4160 for (i
= 0; i
< NrSegments
; i
++)
4162 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4164 if (Segment
== &SectionSegments
[i
])
4166 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4171 if (i
>= NrSegments
)
4173 KeBugCheck(MEMORY_MANAGEMENT
);
4176 for (i
= 0; i
< NrSegments
; i
++)
4178 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4180 PVOID SBaseAddress
= (PVOID
)
4181 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4183 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4189 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4192 MmUnlockAddressSpace(AddressSpace
);
4194 /* Notify debugger */
4195 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4197 return(STATUS_SUCCESS
);
4200 /**********************************************************************
4202 * NtUnmapViewOfSection
4217 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4221 KPROCESSOR_MODE PreviousMode
;
4224 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4225 ProcessHandle
, BaseAddress
);
4227 PreviousMode
= ExGetPreviousMode();
4229 DPRINT("Referencing process\n");
4230 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4231 PROCESS_VM_OPERATION
,
4234 (PVOID
*)(PVOID
)&Process
,
4236 if (!NT_SUCCESS(Status
))
4238 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4242 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4244 ObDereferenceObject(Process
);
4251 * Queries the information of a section object.
4253 * @param SectionHandle
4254 * Handle to the section object. It must be opened with SECTION_QUERY
4256 * @param SectionInformationClass
4257 * Index to a certain information structure. Can be either
4258 * SectionBasicInformation or SectionImageInformation. The latter
4259 * is valid only for sections that were created with the SEC_IMAGE
4261 * @param SectionInformation
4262 * Caller supplies storage for resulting information.
4264 * Size of the supplied storage.
4265 * @param ResultLength
4273 NtQuerySection(IN HANDLE SectionHandle
,
4274 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4275 OUT PVOID SectionInformation
,
4276 IN ULONG SectionInformationLength
,
4277 OUT PULONG ResultLength OPTIONAL
)
4279 PROS_SECTION_OBJECT Section
;
4280 KPROCESSOR_MODE PreviousMode
;
4284 PreviousMode
= ExGetPreviousMode();
4286 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4288 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4290 SectionInformationLength
,
4294 if(!NT_SUCCESS(Status
))
4296 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4300 Status
= ObReferenceObjectByHandle(SectionHandle
,
4302 MmSectionObjectType
,
4304 (PVOID
*)(PVOID
)&Section
,
4306 if (NT_SUCCESS(Status
))
4308 switch (SectionInformationClass
)
4310 case SectionBasicInformation
:
4312 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4316 Sbi
->Attributes
= Section
->AllocationAttributes
;
4317 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4319 Sbi
->BaseAddress
= 0;
4320 Sbi
->Size
.QuadPart
= 0;
4324 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4325 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4328 if (ResultLength
!= NULL
)
4330 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4332 Status
= STATUS_SUCCESS
;
4334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4336 Status
= _SEH2_GetExceptionCode();
4343 case SectionImageInformation
:
4345 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4349 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4350 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4352 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4353 ImageSectionObject
= Section
->ImageSection
;
4355 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4356 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4357 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4358 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4359 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4360 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4361 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4362 Sii
->Machine
= ImageSectionObject
->Machine
;
4363 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4366 if (ResultLength
!= NULL
)
4368 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4370 Status
= STATUS_SUCCESS
;
4372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4374 Status
= _SEH2_GetExceptionCode();
4382 ObDereferenceObject(Section
);
4390 * Extends size of file backed section.
4392 * @param SectionHandle
4393 * Handle to the section object. It must be opened with
4394 * SECTION_EXTEND_SIZE access.
4395 * @param NewMaximumSize
4396 * New maximum size of the section in bytes.
4400 * @todo Move the actual code to internal function MmExtendSection.
4404 NtExtendSection(IN HANDLE SectionHandle
,
4405 IN PLARGE_INTEGER NewMaximumSize
)
4407 LARGE_INTEGER SafeNewMaximumSize
;
4408 PROS_SECTION_OBJECT Section
;
4409 KPROCESSOR_MODE PreviousMode
;
4412 PreviousMode
= ExGetPreviousMode();
4414 if(PreviousMode
!= KernelMode
)
4418 /* make a copy on the stack */
4419 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4420 NewMaximumSize
= &SafeNewMaximumSize
;
4422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4424 /* Return the exception code */
4425 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4430 Status
= ObReferenceObjectByHandle(SectionHandle
,
4431 SECTION_EXTEND_SIZE
,
4432 MmSectionObjectType
,
4436 if (!NT_SUCCESS(Status
))
4441 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4443 ObDereferenceObject(Section
);
4444 return STATUS_INVALID_PARAMETER
;
4448 * - Acquire file extneding resource.
4449 * - Check if we're not resizing the section below it's actual size!
4450 * - Extend segments if needed.
4451 * - Set file information (FileAllocationInformation) to the new size.
4452 * - Release file extending resource.
4455 ObDereferenceObject(Section
);
4457 return STATUS_NOT_IMPLEMENTED
;
4461 /**********************************************************************
4463 * MmAllocateSection@4
4473 * Code taken from ntoskrnl/mm/special.c.
4478 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4483 PMMSUPPORT AddressSpace
;
4484 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4486 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4488 BoundaryAddressMultiple
.QuadPart
= 0;
4490 AddressSpace
= MmGetKernelAddressSpace();
4491 Result
= BaseAddress
;
4492 MmLockAddressSpace(AddressSpace
);
4493 Status
= MmCreateMemoryArea (AddressSpace
,
4501 BoundaryAddressMultiple
);
4502 MmUnlockAddressSpace(AddressSpace
);
4504 if (!NT_SUCCESS(Status
))
4508 DPRINT("Result %p\n",Result
);
4510 /* Create a virtual mapping for this memory area */
4511 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4513 return ((PVOID
)Result
);
4517 /**********************************************************************
4519 * MmMapViewOfSection
4522 * Maps a view of a section into the virtual address space of a
4527 * Pointer to the section object.
4530 * Pointer to the process.
4533 * Desired base address (or NULL) on entry;
4534 * Actual base address of the view on exit.
4537 * Number of high order address bits that must be zero.
4540 * Size in bytes of the initially committed section of
4544 * Offset in bytes from the beginning of the section
4545 * to the beginning of the view.
4548 * Desired length of map (or zero to map all) on entry
4549 * Actual length mapped on exit.
4551 * InheritDisposition
4552 * Specified how the view is to be shared with
4556 * Type of allocation for the pages.
4559 * Protection for the committed region of the view.
4567 MmMapViewOfSection(IN PVOID SectionObject
,
4568 IN PEPROCESS Process
,
4569 IN OUT PVOID
*BaseAddress
,
4570 IN ULONG_PTR ZeroBits
,
4571 IN SIZE_T CommitSize
,
4572 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4573 IN OUT PSIZE_T ViewSize
,
4574 IN SECTION_INHERIT InheritDisposition
,
4575 IN ULONG AllocationType
,
4578 PROS_SECTION_OBJECT Section
;
4579 PMMSUPPORT AddressSpace
;
4581 NTSTATUS Status
= STATUS_SUCCESS
;
4585 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4587 return STATUS_INVALID_PAGE_PROTECTION
;
4591 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4592 AddressSpace
= &Process
->Vm
;
4594 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4596 MmLockAddressSpace(AddressSpace
);
4598 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4602 ULONG_PTR ImageBase
;
4604 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4605 PMM_SECTION_SEGMENT SectionSegments
;
4607 ImageSectionObject
= Section
->ImageSection
;
4608 SectionSegments
= ImageSectionObject
->Segments
;
4609 NrSegments
= ImageSectionObject
->NrSegments
;
4612 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4615 ImageBase
= ImageSectionObject
->ImageBase
;
4619 for (i
= 0; i
< NrSegments
; i
++)
4621 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4623 ULONG_PTR MaxExtent
;
4624 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4625 SectionSegments
[i
].Length
;
4626 ImageSize
= max(ImageSize
, MaxExtent
);
4630 ImageSectionObject
->ImageSize
= ImageSize
;
4632 /* Check there is enough space to map the section at that point. */
4633 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4634 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4636 /* Fail if the user requested a fixed base address. */
4637 if ((*BaseAddress
) != NULL
)
4639 MmUnlockAddressSpace(AddressSpace
);
4640 return(STATUS_UNSUCCESSFUL
);
4642 /* Otherwise find a gap to map the image. */
4643 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4646 MmUnlockAddressSpace(AddressSpace
);
4647 return(STATUS_UNSUCCESSFUL
);
4651 for (i
= 0; i
< NrSegments
; i
++)
4653 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4655 PVOID SBaseAddress
= (PVOID
)
4656 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4657 MmLockSectionSegment(&SectionSegments
[i
]);
4658 Status
= MmMapViewOfSegment(AddressSpace
,
4660 &SectionSegments
[i
],
4662 SectionSegments
[i
].Length
,
4663 SectionSegments
[i
].Protection
,
4666 MmUnlockSectionSegment(&SectionSegments
[i
]);
4667 if (!NT_SUCCESS(Status
))
4669 MmUnlockAddressSpace(AddressSpace
);
4675 *BaseAddress
= (PVOID
)ImageBase
;
4679 /* check for write access */
4680 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4681 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4683 MmUnlockAddressSpace(AddressSpace
);
4684 return STATUS_SECTION_PROTECTION
;
4686 /* check for read access */
4687 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4688 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4690 MmUnlockAddressSpace(AddressSpace
);
4691 return STATUS_SECTION_PROTECTION
;
4693 /* check for execute access */
4694 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4695 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4697 MmUnlockAddressSpace(AddressSpace
);
4698 return STATUS_SECTION_PROTECTION
;
4701 if (ViewSize
== NULL
)
4703 /* Following this pointer would lead to us to the dark side */
4704 /* What to do? Bugcheck? Return status? Do the mambo? */
4705 KeBugCheck(MEMORY_MANAGEMENT
);
4708 if (SectionOffset
== NULL
)
4714 ViewOffset
= SectionOffset
->u
.LowPart
;
4717 if ((ViewOffset
% PAGE_SIZE
) != 0)
4719 MmUnlockAddressSpace(AddressSpace
);
4720 return(STATUS_MAPPED_ALIGNMENT
);
4723 if ((*ViewSize
) == 0)
4725 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4727 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4729 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4732 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4734 MmLockSectionSegment(Section
->Segment
);
4735 Status
= MmMapViewOfSegment(AddressSpace
,
4742 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4743 MmUnlockSectionSegment(Section
->Segment
);
4744 if (!NT_SUCCESS(Status
))
4746 MmUnlockAddressSpace(AddressSpace
);
4751 MmUnlockAddressSpace(AddressSpace
);
4753 return(STATUS_SUCCESS
);
4760 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4761 IN PLARGE_INTEGER NewFileSize
)
4763 /* Check whether an ImageSectionObject exists */
4764 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4766 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4770 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4772 PMM_SECTION_SEGMENT Segment
;
4774 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4777 if (Segment
->ReferenceCount
!= 0)
4779 /* Check size of file */
4780 if (SectionObjectPointer
->SharedCacheMap
)
4782 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4783 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4791 /* Something must gone wrong
4792 * how can we have a Section but no
4794 DPRINT1("ERROR: DataSectionObject without reference!\n");
4798 DPRINT("FIXME: didn't check for outstanding write probes\n");
4808 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4818 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4819 IN MMFLUSH_TYPE FlushType
)
4823 case MmFlushForDelete
:
4824 if (SectionObjectPointer
->ImageSectionObject
||
4825 SectionObjectPointer
->DataSectionObject
)
4829 CcRosSetRemoveOnClose(SectionObjectPointer
);
4831 case MmFlushForWrite
:
4841 MmForceSectionClosed (
4842 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4843 IN BOOLEAN DelayClose
)
4854 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4855 OUT PVOID
* MappedBase
,
4856 IN OUT PULONG ViewSize
)
4858 PROS_SECTION_OBJECT Section
;
4859 PMMSUPPORT AddressSpace
;
4862 DPRINT("MmMapViewInSystemSpace() called\n");
4864 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4865 AddressSpace
= MmGetKernelAddressSpace();
4867 MmLockAddressSpace(AddressSpace
);
4870 if ((*ViewSize
) == 0)
4872 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4874 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4876 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4879 MmLockSectionSegment(Section
->Segment
);
4882 Status
= MmMapViewOfSegment(AddressSpace
,
4891 MmUnlockSectionSegment(Section
->Segment
);
4892 MmUnlockAddressSpace(AddressSpace
);
4902 MmMapViewInSessionSpace (
4904 OUT PVOID
*MappedBase
,
4905 IN OUT PSIZE_T ViewSize
4909 return STATUS_NOT_IMPLEMENTED
;
4917 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4919 PMMSUPPORT AddressSpace
;
4922 DPRINT("MmUnmapViewInSystemSpace() called\n");
4924 AddressSpace
= MmGetKernelAddressSpace();
4926 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4936 MmUnmapViewInSessionSpace (
4941 return STATUS_NOT_IMPLEMENTED
;
4948 MmSetBankedSection (ULONG Unknown0
,
4956 return (STATUS_NOT_IMPLEMENTED
);
4960 /**********************************************************************
4965 * Creates a section object.
4968 * SectionObject (OUT)
4969 * Caller supplied storage for the resulting pointer
4970 * to a SECTION_OBJECT instance;
4973 * Specifies the desired access to the section can be a
4975 * STANDARD_RIGHTS_REQUIRED |
4977 * SECTION_MAP_WRITE |
4978 * SECTION_MAP_READ |
4979 * SECTION_MAP_EXECUTE
4981 * ObjectAttributes [OPTIONAL]
4982 * Initialized attributes for the object can be used
4983 * to create a named section;
4986 * Maximizes the size of the memory section. Must be
4987 * non-NULL for a page-file backed section.
4988 * If value specified for a mapped file and the file is
4989 * not large enough, file will be extended.
4991 * SectionPageProtection
4992 * Can be a combination of:
4998 * AllocationAttributes
4999 * Can be a combination of:
5004 * Handle to a file to create a section mapped to a file
5005 * instead of a memory backed section;
5016 MmCreateSection (OUT PVOID
* Section
,
5017 IN ACCESS_MASK DesiredAccess
,
5018 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5019 IN PLARGE_INTEGER MaximumSize
,
5020 IN ULONG SectionPageProtection
,
5021 IN ULONG AllocationAttributes
,
5022 IN HANDLE FileHandle OPTIONAL
,
5023 IN PFILE_OBJECT File OPTIONAL
)
5026 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5029 * Check the protection
5031 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5032 if (Protection
!= PAGE_READONLY
&&
5033 Protection
!= PAGE_READWRITE
&&
5034 Protection
!= PAGE_WRITECOPY
&&
5035 Protection
!= PAGE_EXECUTE
&&
5036 Protection
!= PAGE_EXECUTE_READ
&&
5037 Protection
!= PAGE_EXECUTE_READWRITE
&&
5038 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5040 return STATUS_INVALID_PAGE_PROTECTION
;
5043 if (AllocationAttributes
& SEC_IMAGE
)
5045 return(MmCreateImageSection(SectionObject
,
5049 SectionPageProtection
,
5050 AllocationAttributes
,
5054 if (FileHandle
!= NULL
)
5056 return(MmCreateDataFileSection(SectionObject
,
5060 SectionPageProtection
,
5061 AllocationAttributes
,
5065 return(MmCreatePageFileSection(SectionObject
,
5069 SectionPageProtection
,
5070 AllocationAttributes
));
5075 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5076 IN OUT PULONG_PTR NumberOfPages
,
5077 IN OUT PULONG_PTR UserPfnArray
)
5080 return STATUS_NOT_IMPLEMENTED
;
5085 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5086 IN ULONG_PTR NumberOfPages
,
5087 IN OUT PULONG_PTR UserPfnArray
)
5090 return STATUS_NOT_IMPLEMENTED
;
5095 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5096 IN ULONG_PTR NumberOfPages
,
5097 IN OUT PULONG_PTR UserPfnArray
)
5100 return STATUS_NOT_IMPLEMENTED
;
5105 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5106 IN OUT PULONG_PTR NumberOfPages
,
5107 IN OUT PULONG_PTR UserPfnArray
)
5110 return STATUS_NOT_IMPLEMENTED
;
5115 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5116 IN PVOID File2MappedAsFile
)
5119 return STATUS_NOT_IMPLEMENTED
;