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 MiCopyFromUserPage(PFN_TYPE DestPage
, PVOID SourceAddress
)
585 Process
= PsGetCurrentProcess();
586 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
587 if (TempAddress
== NULL
)
589 return(STATUS_NO_MEMORY
);
591 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
592 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
593 return(STATUS_SUCCESS
);
598 MiReadPage(PMEMORY_AREA MemoryArea
,
602 * FUNCTION: Read a page for a section backed memory area.
604 * MemoryArea - Memory area to read the page for.
605 * Offset - Offset of the page to read.
606 * Page - Variable that receives a page contains the read data.
613 PCACHE_SEGMENT CacheSeg
;
614 PFILE_OBJECT FileObject
;
618 BOOLEAN IsImageSection
;
621 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
622 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
623 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
624 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
625 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
629 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
632 * If the file system is letting us go directly to the cache and the
633 * memory area was mapped at an offset in the file which is page aligned
634 * then get the related cache segment.
636 if ((FileOffset
% PAGE_SIZE
) == 0 &&
637 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
638 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
642 * Get the related cache segment; we use a lower level interface than
643 * filesystems do because it is safe for us to use an offset with a
644 * alignment less than the file system block size.
646 Status
= CcRosGetCacheSegment(Bcb
,
652 if (!NT_SUCCESS(Status
))
659 * If the cache segment isn't up to date then call the file
660 * system to read in the data.
662 Status
= ReadCacheSegment(CacheSeg
);
663 if (!NT_SUCCESS(Status
))
665 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
670 * Retrieve the page from the cache segment that we actually want.
672 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
673 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
675 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
682 ULONG CacheSegOffset
;
685 * Allocate a page, this is rather complicated by the possibility
686 * we might have to move other things out of memory
688 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
689 if (!NT_SUCCESS(Status
))
693 Status
= CcRosGetCacheSegment(Bcb
,
699 if (!NT_SUCCESS(Status
))
706 * If the cache segment isn't up to date then call the file
707 * system to read in the data.
709 Status
= ReadCacheSegment(CacheSeg
);
710 if (!NT_SUCCESS(Status
))
712 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
717 Process
= PsGetCurrentProcess();
718 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
719 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
720 Length
= RawLength
- SegOffset
;
721 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
723 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
725 else if (CacheSegOffset
>= PAGE_SIZE
)
727 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
731 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
732 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
733 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
734 Status
= CcRosGetCacheSegment(Bcb
,
735 FileOffset
+ CacheSegOffset
,
740 if (!NT_SUCCESS(Status
))
747 * If the cache segment isn't up to date then call the file
748 * system to read in the data.
750 Status
= ReadCacheSegment(CacheSeg
);
751 if (!NT_SUCCESS(Status
))
753 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
757 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
758 if (Length
< PAGE_SIZE
)
760 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
764 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
767 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
768 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
770 return(STATUS_SUCCESS
);
775 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
776 MEMORY_AREA
* MemoryArea
,
784 PROS_SECTION_OBJECT Section
;
785 PMM_SECTION_SEGMENT Segment
;
791 BOOLEAN HasSwapEntry
;
792 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
796 * There is a window between taking the page fault and locking the
797 * address space when another thread could load the page so we check
800 if (MmIsPagePresent(Process
, Address
))
804 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
805 MmLockPage(MmGetPfnForProcess(Process
, Address
));
806 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
808 return(STATUS_SUCCESS
);
811 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
812 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
813 + MemoryArea
->Data
.SectionData
.ViewOffset
;
815 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
816 Section
= MemoryArea
->Data
.SectionData
.Section
;
817 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
818 &MemoryArea
->Data
.SectionData
.RegionListHead
,
823 MmLockSectionSegment(Segment
);
826 * Check if this page needs to be mapped COW
828 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
829 (Region
->Protect
== PAGE_READWRITE
||
830 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
832 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
836 Attributes
= Region
->Protect
;
840 * Get or create a page operation descriptor
842 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
845 DPRINT1("MmGetPageOp failed\n");
846 KeBugCheck(MEMORY_MANAGEMENT
);
850 * Check if someone else is already handling this fault, if so wait
853 if (PageOp
->Thread
!= PsGetCurrentThread())
855 MmUnlockSectionSegment(Segment
);
856 MmUnlockAddressSpace(AddressSpace
);
857 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
859 * Check for various strange conditions
861 if (Status
!= STATUS_SUCCESS
)
863 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
864 KeBugCheck(MEMORY_MANAGEMENT
);
866 if (PageOp
->Status
== STATUS_PENDING
)
868 DPRINT1("Woke for page op before completion\n");
869 KeBugCheck(MEMORY_MANAGEMENT
);
871 MmLockAddressSpace(AddressSpace
);
873 * If this wasn't a pagein then restart the operation
875 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
877 MmspCompleteAndReleasePageOp(PageOp
);
878 DPRINT("Address 0x%.8X\n", Address
);
879 return(STATUS_MM_RESTART_OPERATION
);
883 * If the thread handling this fault has failed then we don't retry
885 if (!NT_SUCCESS(PageOp
->Status
))
887 Status
= PageOp
->Status
;
888 MmspCompleteAndReleasePageOp(PageOp
);
889 DPRINT("Address 0x%.8X\n", Address
);
892 MmLockSectionSegment(Segment
);
894 * If the completed fault was for another address space then set the
897 if (!MmIsPagePresent(Process
, Address
))
899 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
900 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
902 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
905 * The page was a private page in another or in our address space
907 MmUnlockSectionSegment(Segment
);
908 MmspCompleteAndReleasePageOp(PageOp
);
909 return(STATUS_MM_RESTART_OPERATION
);
912 Page
= PFN_FROM_SSE(Entry
);
914 MmSharePageEntrySectionSegment(Segment
, Offset
);
916 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
917 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
919 Status
= MmCreateVirtualMapping(Process
,
924 if (!NT_SUCCESS(Status
))
926 DPRINT1("Unable to create virtual mapping\n");
927 KeBugCheck(MEMORY_MANAGEMENT
);
929 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
933 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
935 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
937 MmUnlockSectionSegment(Segment
);
938 PageOp
->Status
= STATUS_SUCCESS
;
939 MmspCompleteAndReleasePageOp(PageOp
);
940 DPRINT("Address 0x%.8X\n", Address
);
941 return(STATUS_SUCCESS
);
944 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
948 * Must be private page we have swapped out.
955 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
957 DPRINT1("Found a swaped out private page in a pagefile section.\n");
958 KeBugCheck(MEMORY_MANAGEMENT
);
961 MmUnlockSectionSegment(Segment
);
962 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
964 MmUnlockAddressSpace(AddressSpace
);
965 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
966 if (!NT_SUCCESS(Status
))
968 KeBugCheck(MEMORY_MANAGEMENT
);
971 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
972 if (!NT_SUCCESS(Status
))
974 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
975 KeBugCheck(MEMORY_MANAGEMENT
);
977 MmLockAddressSpace(AddressSpace
);
978 Status
= MmCreateVirtualMapping(Process
,
983 if (!NT_SUCCESS(Status
))
985 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
986 KeBugCheck(MEMORY_MANAGEMENT
);
991 * Store the swap entry for later use.
993 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
996 * Add the page to the process's working set
998 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1001 * Finish the operation
1005 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1007 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1009 PageOp
->Status
= STATUS_SUCCESS
;
1010 MmspCompleteAndReleasePageOp(PageOp
);
1011 DPRINT("Address 0x%.8X\n", Address
);
1012 return(STATUS_SUCCESS
);
1016 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1018 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1020 MmUnlockSectionSegment(Segment
);
1022 * Just map the desired physical page
1024 Page
= Offset
>> PAGE_SHIFT
;
1025 Status
= MmCreateVirtualMappingUnsafe(Process
,
1030 if (!NT_SUCCESS(Status
))
1032 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1033 KeBugCheck(MEMORY_MANAGEMENT
);
1037 * Don't add an rmap entry since the page mapped could be for
1042 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1044 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1048 * Cleanup and release locks
1050 PageOp
->Status
= STATUS_SUCCESS
;
1051 MmspCompleteAndReleasePageOp(PageOp
);
1052 DPRINT("Address 0x%.8X\n", Address
);
1053 return(STATUS_SUCCESS
);
1057 * Map anonymous memory for BSS sections
1059 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1061 MmUnlockSectionSegment(Segment
);
1062 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1063 if (!NT_SUCCESS(Status
))
1065 MmUnlockAddressSpace(AddressSpace
);
1066 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1067 MmLockAddressSpace(AddressSpace
);
1069 if (!NT_SUCCESS(Status
))
1071 KeBugCheck(MEMORY_MANAGEMENT
);
1073 Status
= MmCreateVirtualMapping(Process
,
1078 if (!NT_SUCCESS(Status
))
1080 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1081 KeBugCheck(MEMORY_MANAGEMENT
);
1084 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1087 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1089 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1093 * Cleanup and release locks
1095 PageOp
->Status
= STATUS_SUCCESS
;
1096 MmspCompleteAndReleasePageOp(PageOp
);
1097 DPRINT("Address 0x%.8X\n", Address
);
1098 return(STATUS_SUCCESS
);
1102 * Get the entry corresponding to the offset within the section
1104 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1109 * If the entry is zero (and it can't change because we have
1110 * locked the segment) then we need to load the page.
1114 * Release all our locks and read in the page from disk
1116 MmUnlockSectionSegment(Segment
);
1117 MmUnlockAddressSpace(AddressSpace
);
1119 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1120 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1122 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1123 if (!NT_SUCCESS(Status
))
1125 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1130 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1131 if (!NT_SUCCESS(Status
))
1133 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1136 if (!NT_SUCCESS(Status
))
1139 * FIXME: What do we know in this case?
1142 * Cleanup and release locks
1144 MmLockAddressSpace(AddressSpace
);
1145 PageOp
->Status
= Status
;
1146 MmspCompleteAndReleasePageOp(PageOp
);
1147 DPRINT("Address 0x%.8X\n", Address
);
1151 * Relock the address space and segment
1153 MmLockAddressSpace(AddressSpace
);
1154 MmLockSectionSegment(Segment
);
1157 * Check the entry. No one should change the status of a page
1158 * that has a pending page-in.
1160 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1161 if (Entry
!= Entry1
)
1163 DPRINT1("Someone changed ppte entry while we slept\n");
1164 KeBugCheck(MEMORY_MANAGEMENT
);
1168 * Mark the offset within the section as having valid, in-memory
1171 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1172 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1173 MmUnlockSectionSegment(Segment
);
1175 Status
= MmCreateVirtualMapping(Process
,
1180 if (!NT_SUCCESS(Status
))
1182 DPRINT1("Unable to create virtual mapping\n");
1183 KeBugCheck(MEMORY_MANAGEMENT
);
1185 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1189 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1191 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1193 PageOp
->Status
= STATUS_SUCCESS
;
1194 MmspCompleteAndReleasePageOp(PageOp
);
1195 DPRINT("Address 0x%.8X\n", Address
);
1196 return(STATUS_SUCCESS
);
1198 else if (IS_SWAP_FROM_SSE(Entry
))
1200 SWAPENTRY SwapEntry
;
1202 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1205 * Release all our locks and read in the page from disk
1207 MmUnlockSectionSegment(Segment
);
1209 MmUnlockAddressSpace(AddressSpace
);
1211 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1212 if (!NT_SUCCESS(Status
))
1214 KeBugCheck(MEMORY_MANAGEMENT
);
1217 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1218 if (!NT_SUCCESS(Status
))
1220 KeBugCheck(MEMORY_MANAGEMENT
);
1224 * Relock the address space and segment
1226 MmLockAddressSpace(AddressSpace
);
1227 MmLockSectionSegment(Segment
);
1230 * Check the entry. No one should change the status of a page
1231 * that has a pending page-in.
1233 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1234 if (Entry
!= Entry1
)
1236 DPRINT1("Someone changed ppte entry while we slept\n");
1237 KeBugCheck(MEMORY_MANAGEMENT
);
1241 * Mark the offset within the section as having valid, in-memory
1244 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1245 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1246 MmUnlockSectionSegment(Segment
);
1249 * Save the swap entry.
1251 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1252 Status
= MmCreateVirtualMapping(Process
,
1257 if (!NT_SUCCESS(Status
))
1259 DPRINT1("Unable to create virtual mapping\n");
1260 KeBugCheck(MEMORY_MANAGEMENT
);
1262 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1265 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1267 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1269 PageOp
->Status
= STATUS_SUCCESS
;
1270 MmspCompleteAndReleasePageOp(PageOp
);
1271 DPRINT("Address 0x%.8X\n", Address
);
1272 return(STATUS_SUCCESS
);
1277 * If the section offset is already in-memory and valid then just
1278 * take another reference to the page
1281 Page
= PFN_FROM_SSE(Entry
);
1283 MmSharePageEntrySectionSegment(Segment
, Offset
);
1284 MmUnlockSectionSegment(Segment
);
1286 Status
= MmCreateVirtualMapping(Process
,
1291 if (!NT_SUCCESS(Status
))
1293 DPRINT1("Unable to create virtual mapping\n");
1294 KeBugCheck(MEMORY_MANAGEMENT
);
1296 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1299 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1301 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1303 PageOp
->Status
= STATUS_SUCCESS
;
1304 MmspCompleteAndReleasePageOp(PageOp
);
1305 DPRINT("Address 0x%.8X\n", Address
);
1306 return(STATUS_SUCCESS
);
1312 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1313 MEMORY_AREA
* MemoryArea
,
1317 PMM_SECTION_SEGMENT Segment
;
1318 PROS_SECTION_OBJECT Section
;
1327 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1330 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1333 * Check if the page has been paged out or has already been set readwrite
1335 if (!MmIsPagePresent(Process
, Address
) ||
1336 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1338 DPRINT("Address 0x%.8X\n", Address
);
1339 return(STATUS_SUCCESS
);
1343 * Find the offset of the page
1345 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1346 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1347 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1349 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1350 Section
= MemoryArea
->Data
.SectionData
.Section
;
1351 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1352 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1357 MmLockSectionSegment(Segment
);
1359 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1360 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1362 MmUnlockSectionSegment(Segment
);
1365 * Check if we are doing COW
1367 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1368 (Region
->Protect
== PAGE_READWRITE
||
1369 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1371 DPRINT("Address 0x%.8X\n", Address
);
1372 return(STATUS_ACCESS_VIOLATION
);
1375 if (IS_SWAP_FROM_SSE(Entry
) ||
1376 PFN_FROM_SSE(Entry
) != OldPage
)
1378 /* This is a private page. We must only change the page protection. */
1379 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1380 return(STATUS_SUCCESS
);
1384 * Get or create a pageop
1386 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1387 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1390 DPRINT1("MmGetPageOp failed\n");
1391 KeBugCheck(MEMORY_MANAGEMENT
);
1395 * Wait for any other operations to complete
1397 if (PageOp
->Thread
!= PsGetCurrentThread())
1399 MmUnlockAddressSpace(AddressSpace
);
1400 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1402 * Check for various strange conditions
1404 if (Status
== STATUS_TIMEOUT
)
1406 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1407 KeBugCheck(MEMORY_MANAGEMENT
);
1409 if (PageOp
->Status
== STATUS_PENDING
)
1411 DPRINT1("Woke for page op before completion\n");
1412 KeBugCheck(MEMORY_MANAGEMENT
);
1415 * Restart the operation
1417 MmLockAddressSpace(AddressSpace
);
1418 MmspCompleteAndReleasePageOp(PageOp
);
1419 DPRINT("Address 0x%.8X\n", Address
);
1420 return(STATUS_MM_RESTART_OPERATION
);
1424 * Release locks now we have the pageop
1426 MmUnlockAddressSpace(AddressSpace
);
1431 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1432 if (!NT_SUCCESS(Status
))
1434 KeBugCheck(MEMORY_MANAGEMENT
);
1440 MiCopyFromUserPage(NewPage
, PAddress
);
1442 MmLockAddressSpace(AddressSpace
);
1444 * Delete the old entry.
1446 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1449 * Set the PTE to point to the new page
1451 Status
= MmCreateVirtualMapping(Process
,
1456 if (!NT_SUCCESS(Status
))
1458 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1459 KeBugCheck(MEMORY_MANAGEMENT
);
1462 if (!NT_SUCCESS(Status
))
1464 DPRINT1("Unable to create virtual mapping\n");
1465 KeBugCheck(MEMORY_MANAGEMENT
);
1469 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1470 MmLockPage(NewPage
);
1471 MmUnlockPage(OldPage
);
1472 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1476 * Unshare the old page.
1478 MmDeleteRmap(OldPage
, Process
, PAddress
);
1479 MmInsertRmap(NewPage
, Process
, PAddress
);
1480 MmLockSectionSegment(Segment
);
1481 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1482 MmUnlockSectionSegment(Segment
);
1484 PageOp
->Status
= STATUS_SUCCESS
;
1485 MmspCompleteAndReleasePageOp(PageOp
);
1486 DPRINT("Address 0x%.8X\n", Address
);
1487 return(STATUS_SUCCESS
);
1491 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1493 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1497 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1500 MmLockAddressSpace(&Process
->Vm
);
1503 MmDeleteVirtualMapping(Process
,
1510 PageOutContext
->WasDirty
= TRUE
;
1512 if (!PageOutContext
->Private
)
1514 MmLockSectionSegment(PageOutContext
->Segment
);
1515 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1516 PageOutContext
->Segment
,
1517 PageOutContext
->Offset
,
1518 PageOutContext
->WasDirty
,
1520 MmUnlockSectionSegment(PageOutContext
->Segment
);
1524 MmUnlockAddressSpace(&Process
->Vm
);
1527 if (PageOutContext
->Private
)
1529 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1532 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1537 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1538 MEMORY_AREA
* MemoryArea
,
1543 MM_SECTION_PAGEOUT_CONTEXT Context
;
1544 SWAPENTRY SwapEntry
;
1548 PFILE_OBJECT FileObject
;
1550 BOOLEAN DirectMapped
;
1551 BOOLEAN IsImageSection
;
1552 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1555 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1558 * Get the segment and section.
1560 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1561 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1563 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1564 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1565 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1567 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1569 FileObject
= Context
.Section
->FileObject
;
1570 DirectMapped
= FALSE
;
1571 if (FileObject
!= NULL
&&
1572 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1574 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1577 * If the file system is letting us go directly to the cache and the
1578 * memory area was mapped at an offset in the file which is page aligned
1579 * then note this is a direct mapped page.
1581 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1582 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1584 DirectMapped
= TRUE
;
1590 * This should never happen since mappings of physical memory are never
1591 * placed in the rmap lists.
1593 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1595 DPRINT1("Trying to page out from physical memory section address 0x%X "
1596 "process %d\n", Address
,
1597 Process
? Process
->UniqueProcessId
: 0);
1598 KeBugCheck(MEMORY_MANAGEMENT
);
1602 * Get the section segment entry and the physical address.
1604 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1605 if (!MmIsPagePresent(Process
, Address
))
1607 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1608 Process
? Process
->UniqueProcessId
: 0, Address
);
1609 KeBugCheck(MEMORY_MANAGEMENT
);
1611 Page
= MmGetPfnForProcess(Process
, Address
);
1612 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1615 * Prepare the context structure for the rmap delete call.
1617 Context
.WasDirty
= FALSE
;
1618 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1619 IS_SWAP_FROM_SSE(Entry
) ||
1620 PFN_FROM_SSE(Entry
) != Page
)
1622 Context
.Private
= TRUE
;
1626 Context
.Private
= FALSE
;
1630 * Take an additional reference to the page or the cache segment.
1632 if (DirectMapped
&& !Context
.Private
)
1634 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1636 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1637 KeBugCheck(MEMORY_MANAGEMENT
);
1642 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1643 MmReferencePage(Page
);
1644 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1647 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1650 * If this wasn't a private page then we should have reduced the entry to
1651 * zero by deleting all the rmaps.
1653 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1655 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1656 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1658 KeBugCheck(MEMORY_MANAGEMENT
);
1663 * If the page wasn't dirty then we can just free it as for a readonly page.
1664 * Since we unmapped all the mappings above we know it will not suddenly
1666 * If the page is from a pagefile section and has no swap entry,
1667 * we can't free the page at this point.
1669 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1670 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1672 if (Context
.Private
)
1674 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1675 Context
.WasDirty
? "dirty" : "clean", Address
);
1676 KeBugCheck(MEMORY_MANAGEMENT
);
1678 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1680 MmSetSavedSwapEntryPage(Page
, 0);
1681 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1682 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1683 PageOp
->Status
= STATUS_SUCCESS
;
1684 MmspCompleteAndReleasePageOp(PageOp
);
1685 return(STATUS_SUCCESS
);
1688 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1690 if (Context
.Private
)
1692 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1693 Context
.WasDirty
? "dirty" : "clean", Address
);
1694 KeBugCheck(MEMORY_MANAGEMENT
);
1696 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1698 MmSetSavedSwapEntryPage(Page
, 0);
1701 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1703 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1704 PageOp
->Status
= STATUS_SUCCESS
;
1705 MmspCompleteAndReleasePageOp(PageOp
);
1706 return(STATUS_SUCCESS
);
1709 else if (!Context
.Private
&& DirectMapped
)
1713 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1715 KeBugCheck(MEMORY_MANAGEMENT
);
1717 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1718 if (!NT_SUCCESS(Status
))
1720 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1721 KeBugCheck(MEMORY_MANAGEMENT
);
1723 PageOp
->Status
= STATUS_SUCCESS
;
1724 MmspCompleteAndReleasePageOp(PageOp
);
1725 return(STATUS_SUCCESS
);
1727 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1731 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1733 KeBugCheck(MEMORY_MANAGEMENT
);
1735 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1736 PageOp
->Status
= STATUS_SUCCESS
;
1737 MmspCompleteAndReleasePageOp(PageOp
);
1738 return(STATUS_SUCCESS
);
1740 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1742 MmSetSavedSwapEntryPage(Page
, 0);
1743 MmLockAddressSpace(AddressSpace
);
1744 Status
= MmCreatePageFileMapping(Process
,
1747 MmUnlockAddressSpace(AddressSpace
);
1748 if (!NT_SUCCESS(Status
))
1750 KeBugCheck(MEMORY_MANAGEMENT
);
1752 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1753 PageOp
->Status
= STATUS_SUCCESS
;
1754 MmspCompleteAndReleasePageOp(PageOp
);
1755 return(STATUS_SUCCESS
);
1759 * If necessary, allocate an entry in the paging file for this page
1763 SwapEntry
= MmAllocSwapPage();
1766 MmShowOutOfSpaceMessagePagingFile();
1767 MmLockAddressSpace(AddressSpace
);
1769 * For private pages restore the old mappings.
1771 if (Context
.Private
)
1773 Status
= MmCreateVirtualMapping(Process
,
1775 MemoryArea
->Protect
,
1778 MmSetDirtyPage(Process
, Address
);
1786 * For non-private pages if the page wasn't direct mapped then
1787 * set it back into the section segment entry so we don't loose
1788 * our copy. Otherwise it will be handled by the cache manager.
1790 Status
= MmCreateVirtualMapping(Process
,
1792 MemoryArea
->Protect
,
1795 MmSetDirtyPage(Process
, Address
);
1799 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1800 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1802 MmUnlockAddressSpace(AddressSpace
);
1803 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1804 MmspCompleteAndReleasePageOp(PageOp
);
1805 return(STATUS_PAGEFILE_QUOTA
);
1810 * Write the page to the pagefile
1812 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1813 if (!NT_SUCCESS(Status
))
1815 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1818 * As above: undo our actions.
1819 * FIXME: Also free the swap page.
1821 MmLockAddressSpace(AddressSpace
);
1822 if (Context
.Private
)
1824 Status
= MmCreateVirtualMapping(Process
,
1826 MemoryArea
->Protect
,
1829 MmSetDirtyPage(Process
, Address
);
1836 Status
= MmCreateVirtualMapping(Process
,
1838 MemoryArea
->Protect
,
1841 MmSetDirtyPage(Process
, Address
);
1845 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1846 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1848 MmUnlockAddressSpace(AddressSpace
);
1849 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1850 MmspCompleteAndReleasePageOp(PageOp
);
1851 return(STATUS_UNSUCCESSFUL
);
1855 * Otherwise we have succeeded.
1857 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1858 MmSetSavedSwapEntryPage(Page
, 0);
1859 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1860 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1862 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1866 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1869 if (Context
.Private
)
1871 MmLockAddressSpace(AddressSpace
);
1872 Status
= MmCreatePageFileMapping(Process
,
1875 MmUnlockAddressSpace(AddressSpace
);
1876 if (!NT_SUCCESS(Status
))
1878 KeBugCheck(MEMORY_MANAGEMENT
);
1883 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1884 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1887 PageOp
->Status
= STATUS_SUCCESS
;
1888 MmspCompleteAndReleasePageOp(PageOp
);
1889 return(STATUS_SUCCESS
);
1894 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1895 PMEMORY_AREA MemoryArea
,
1900 PROS_SECTION_OBJECT Section
;
1901 PMM_SECTION_SEGMENT Segment
;
1903 SWAPENTRY SwapEntry
;
1907 PFILE_OBJECT FileObject
;
1909 BOOLEAN DirectMapped
;
1910 BOOLEAN IsImageSection
;
1911 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1913 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1915 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1916 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1919 * Get the segment and section.
1921 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1922 Section
= MemoryArea
->Data
.SectionData
.Section
;
1923 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1925 FileObject
= Section
->FileObject
;
1926 DirectMapped
= FALSE
;
1927 if (FileObject
!= NULL
&&
1928 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1930 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1933 * If the file system is letting us go directly to the cache and the
1934 * memory area was mapped at an offset in the file which is page aligned
1935 * then note this is a direct mapped page.
1937 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1938 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1940 DirectMapped
= TRUE
;
1945 * This should never happen since mappings of physical memory are never
1946 * placed in the rmap lists.
1948 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1950 DPRINT1("Trying to write back page from physical memory mapped at %X "
1951 "process %d\n", Address
,
1952 Process
? Process
->UniqueProcessId
: 0);
1953 KeBugCheck(MEMORY_MANAGEMENT
);
1957 * Get the section segment entry and the physical address.
1959 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1960 if (!MmIsPagePresent(Process
, Address
))
1962 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1963 Process
? Process
->UniqueProcessId
: 0, Address
);
1964 KeBugCheck(MEMORY_MANAGEMENT
);
1966 Page
= MmGetPfnForProcess(Process
, Address
);
1967 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1970 * Check for a private (COWed) page.
1972 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1973 IS_SWAP_FROM_SSE(Entry
) ||
1974 PFN_FROM_SSE(Entry
) != Page
)
1984 * Speculatively set all mappings of the page to clean.
1986 MmSetCleanAllRmaps(Page
);
1989 * If this page was direct mapped from the cache then the cache manager
1990 * will take care of writing it back to disk.
1992 if (DirectMapped
&& !Private
)
1994 ASSERT(SwapEntry
== 0);
1995 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1996 PageOp
->Status
= STATUS_SUCCESS
;
1997 MmspCompleteAndReleasePageOp(PageOp
);
1998 return(STATUS_SUCCESS
);
2002 * If necessary, allocate an entry in the paging file for this page
2006 SwapEntry
= MmAllocSwapPage();
2009 MmSetDirtyAllRmaps(Page
);
2010 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2011 MmspCompleteAndReleasePageOp(PageOp
);
2012 return(STATUS_PAGEFILE_QUOTA
);
2014 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2018 * Write the page to the pagefile
2020 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2021 if (!NT_SUCCESS(Status
))
2023 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2025 MmSetDirtyAllRmaps(Page
);
2026 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2027 MmspCompleteAndReleasePageOp(PageOp
);
2028 return(STATUS_UNSUCCESSFUL
);
2032 * Otherwise we have succeeded.
2034 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2035 PageOp
->Status
= STATUS_SUCCESS
;
2036 MmspCompleteAndReleasePageOp(PageOp
);
2037 return(STATUS_SUCCESS
);
2041 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2049 PMEMORY_AREA MemoryArea
;
2050 PMM_SECTION_SEGMENT Segment
;
2051 BOOLEAN DoCOW
= FALSE
;
2053 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2055 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2056 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2058 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2059 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2064 if (OldProtect
!= NewProtect
)
2066 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2068 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2069 ULONG Protect
= NewProtect
;
2072 * If we doing COW for this segment then check if the page is
2075 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2081 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2082 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2083 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2084 Page
= MmGetPfnForProcess(Process
, Address
);
2086 Protect
= PAGE_READONLY
;
2087 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2088 IS_SWAP_FROM_SSE(Entry
) ||
2089 PFN_FROM_SSE(Entry
) != Page
)
2091 Protect
= NewProtect
;
2095 if (MmIsPagePresent(Process
, Address
))
2097 MmSetPageProtect(Process
, Address
,
2106 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2107 PMEMORY_AREA MemoryArea
,
2115 ULONG_PTR MaxLength
;
2117 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2118 if (Length
> MaxLength
)
2121 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2122 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2124 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2125 Region
->Protect
!= Protect
)
2127 return STATUS_INVALID_PAGE_PROTECTION
;
2130 *OldProtect
= Region
->Protect
;
2131 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2132 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2133 BaseAddress
, Length
, Region
->Type
, Protect
,
2134 MmAlterViewAttributes
);
2140 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2142 PMEMORY_BASIC_INFORMATION Info
,
2143 PSIZE_T ResultLength
)
2146 PVOID RegionBaseAddress
;
2147 PROS_SECTION_OBJECT Section
;
2148 PMM_SECTION_SEGMENT Segment
;
2150 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2151 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2152 Address
, &RegionBaseAddress
);
2155 return STATUS_UNSUCCESSFUL
;
2158 Section
= MemoryArea
->Data
.SectionData
.Section
;
2159 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2161 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2162 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2163 Info
->Type
= MEM_IMAGE
;
2167 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2168 Info
->Type
= MEM_MAPPED
;
2170 Info
->BaseAddress
= RegionBaseAddress
;
2171 Info
->AllocationProtect
= MemoryArea
->Protect
;
2172 Info
->RegionSize
= Region
->Length
;
2173 Info
->State
= MEM_COMMIT
;
2174 Info
->Protect
= Region
->Protect
;
2176 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2177 return(STATUS_SUCCESS
);
2182 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2187 ULONG SavedSwapEntry
;
2192 Length
= PAGE_ROUND_UP(Segment
->Length
);
2193 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2195 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2198 if (IS_SWAP_FROM_SSE(Entry
))
2200 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2204 Page
= PFN_FROM_SSE(Entry
);
2205 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2206 if (SavedSwapEntry
!= 0)
2208 MmSetSavedSwapEntryPage(Page
, 0);
2209 MmFreeSwapPage(SavedSwapEntry
);
2211 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2213 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2219 MmpDeleteSection(PVOID ObjectBody
)
2221 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2223 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2224 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2229 PMM_SECTION_SEGMENT SectionSegments
;
2232 * NOTE: Section->ImageSection can be NULL for short time
2233 * during the section creating. If we fail for some reason
2234 * until the image section is properly initialized we shouldn't
2235 * process further here.
2237 if (Section
->ImageSection
== NULL
)
2240 SectionSegments
= Section
->ImageSection
->Segments
;
2241 NrSegments
= Section
->ImageSection
->NrSegments
;
2243 for (i
= 0; i
< NrSegments
; i
++)
2245 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2247 MmLockSectionSegment(&SectionSegments
[i
]);
2249 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2250 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2254 MmpFreePageFileSegment(&SectionSegments
[i
]);
2256 MmUnlockSectionSegment(&SectionSegments
[i
]);
2263 * NOTE: Section->Segment can be NULL for short time
2264 * during the section creating.
2266 if (Section
->Segment
== NULL
)
2269 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2271 MmpFreePageFileSegment(Section
->Segment
);
2272 MmFreePageTablesSectionSegment(Section
->Segment
);
2273 ExFreePool(Section
->Segment
);
2274 Section
->Segment
= NULL
;
2278 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2281 if (Section
->FileObject
!= NULL
)
2283 CcRosDereferenceCache(Section
->FileObject
);
2284 ObDereferenceObject(Section
->FileObject
);
2285 Section
->FileObject
= NULL
;
2290 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2292 IN ACCESS_MASK GrantedAccess
,
2293 IN ULONG ProcessHandleCount
,
2294 IN ULONG SystemHandleCount
)
2296 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2297 Object
, ProcessHandleCount
);
2303 MmCreatePhysicalMemorySection(VOID
)
2305 PROS_SECTION_OBJECT PhysSection
;
2307 OBJECT_ATTRIBUTES Obj
;
2308 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2309 LARGE_INTEGER SectionSize
;
2313 * Create the section mapping physical memory
2315 SectionSize
.QuadPart
= 0xFFFFFFFF;
2316 InitializeObjectAttributes(&Obj
,
2321 Status
= MmCreateSection((PVOID
)&PhysSection
,
2325 PAGE_EXECUTE_READWRITE
,
2329 if (!NT_SUCCESS(Status
))
2331 DPRINT1("Failed to create PhysicalMemory section\n");
2332 KeBugCheck(MEMORY_MANAGEMENT
);
2334 Status
= ObInsertObject(PhysSection
,
2340 if (!NT_SUCCESS(Status
))
2342 ObDereferenceObject(PhysSection
);
2344 ObCloseHandle(Handle
, KernelMode
);
2345 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2346 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2348 return(STATUS_SUCCESS
);
2354 MmInitSectionImplementation(VOID
)
2356 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2357 UNICODE_STRING Name
;
2359 DPRINT("Creating Section Object Type\n");
2361 /* Initialize the Section object type */
2362 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2363 RtlInitUnicodeString(&Name
, L
"Section");
2364 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2365 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2366 ObjectTypeInitializer
.PoolType
= PagedPool
;
2367 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2368 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2369 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2370 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2371 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2372 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2374 MmCreatePhysicalMemorySection();
2376 return(STATUS_SUCCESS
);
2381 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2382 ACCESS_MASK DesiredAccess
,
2383 POBJECT_ATTRIBUTES ObjectAttributes
,
2384 PLARGE_INTEGER UMaximumSize
,
2385 ULONG SectionPageProtection
,
2386 ULONG AllocationAttributes
)
2388 * Create a section which is backed by the pagefile
2391 LARGE_INTEGER MaximumSize
;
2392 PROS_SECTION_OBJECT Section
;
2393 PMM_SECTION_SEGMENT Segment
;
2396 if (UMaximumSize
== NULL
)
2398 return(STATUS_UNSUCCESSFUL
);
2400 MaximumSize
= *UMaximumSize
;
2403 * Create the section
2405 Status
= ObCreateObject(ExGetPreviousMode(),
2406 MmSectionObjectType
,
2408 ExGetPreviousMode(),
2410 sizeof(ROS_SECTION_OBJECT
),
2413 (PVOID
*)(PVOID
)&Section
);
2414 if (!NT_SUCCESS(Status
))
2422 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2423 Section
->SectionPageProtection
= SectionPageProtection
;
2424 Section
->AllocationAttributes
= AllocationAttributes
;
2425 Section
->MaximumSize
= MaximumSize
;
2426 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2427 TAG_MM_SECTION_SEGMENT
);
2428 if (Segment
== NULL
)
2430 ObDereferenceObject(Section
);
2431 return(STATUS_NO_MEMORY
);
2433 Section
->Segment
= Segment
;
2434 Segment
->ReferenceCount
= 1;
2435 ExInitializeFastMutex(&Segment
->Lock
);
2436 Segment
->FileOffset
= 0;
2437 Segment
->Protection
= SectionPageProtection
;
2438 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2439 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2440 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2441 Segment
->WriteCopy
= FALSE
;
2442 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2443 Segment
->VirtualAddress
= 0;
2444 Segment
->Characteristics
= 0;
2445 *SectionObject
= Section
;
2446 return(STATUS_SUCCESS
);
2452 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2453 ACCESS_MASK DesiredAccess
,
2454 POBJECT_ATTRIBUTES ObjectAttributes
,
2455 PLARGE_INTEGER UMaximumSize
,
2456 ULONG SectionPageProtection
,
2457 ULONG AllocationAttributes
,
2460 * Create a section backed by a data file
2463 PROS_SECTION_OBJECT Section
;
2465 LARGE_INTEGER MaximumSize
;
2466 PFILE_OBJECT FileObject
;
2467 PMM_SECTION_SEGMENT Segment
;
2469 IO_STATUS_BLOCK Iosb
;
2470 LARGE_INTEGER Offset
;
2472 FILE_STANDARD_INFORMATION FileInfo
;
2476 * Create the section
2478 Status
= ObCreateObject(ExGetPreviousMode(),
2479 MmSectionObjectType
,
2481 ExGetPreviousMode(),
2483 sizeof(ROS_SECTION_OBJECT
),
2486 (PVOID
*)(PVOID
)&Section
);
2487 if (!NT_SUCCESS(Status
))
2494 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2495 Section
->SectionPageProtection
= SectionPageProtection
;
2496 Section
->AllocationAttributes
= AllocationAttributes
;
2499 * Check file access required
2501 if (SectionPageProtection
& PAGE_READWRITE
||
2502 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2504 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2508 FileAccess
= FILE_READ_DATA
;
2512 * Reference the file handle
2514 Status
= ObReferenceObjectByHandle(FileHandle
,
2517 ExGetPreviousMode(),
2518 (PVOID
*)(PVOID
)&FileObject
,
2520 if (!NT_SUCCESS(Status
))
2522 ObDereferenceObject(Section
);
2527 * FIXME: This is propably not entirely correct. We can't look into
2528 * the standard FCB header because it might not be initialized yet
2529 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2530 * standard file information is filled on first request).
2532 Status
= IoQueryFileInformation(FileObject
,
2533 FileStandardInformation
,
2534 sizeof(FILE_STANDARD_INFORMATION
),
2537 Iosb
.Information
= Length
;
2538 if (!NT_SUCCESS(Status
))
2540 ObDereferenceObject(Section
);
2541 ObDereferenceObject(FileObject
);
2546 * FIXME: Revise this once a locking order for file size changes is
2549 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2551 MaximumSize
= *UMaximumSize
;
2555 MaximumSize
= FileInfo
.EndOfFile
;
2556 /* Mapping zero-sized files isn't allowed. */
2557 if (MaximumSize
.QuadPart
== 0)
2559 ObDereferenceObject(Section
);
2560 ObDereferenceObject(FileObject
);
2561 return STATUS_FILE_INVALID
;
2565 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2567 Status
= IoSetInformation(FileObject
,
2568 FileAllocationInformation
,
2569 sizeof(LARGE_INTEGER
),
2571 if (!NT_SUCCESS(Status
))
2573 ObDereferenceObject(Section
);
2574 ObDereferenceObject(FileObject
);
2575 return(STATUS_SECTION_NOT_EXTENDED
);
2579 if (FileObject
->SectionObjectPointer
== NULL
||
2580 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2583 * Read a bit so caching is initiated for the file object.
2584 * This is only needed because MiReadPage currently cannot
2585 * handle non-cached streams.
2587 Offset
.QuadPart
= 0;
2588 Status
= ZwReadFile(FileHandle
,
2597 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2599 ObDereferenceObject(Section
);
2600 ObDereferenceObject(FileObject
);
2603 if (FileObject
->SectionObjectPointer
== NULL
||
2604 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2606 /* FIXME: handle this situation */
2607 ObDereferenceObject(Section
);
2608 ObDereferenceObject(FileObject
);
2609 return STATUS_INVALID_PARAMETER
;
2616 Status
= MmspWaitForFileLock(FileObject
);
2617 if (Status
!= STATUS_SUCCESS
)
2619 ObDereferenceObject(Section
);
2620 ObDereferenceObject(FileObject
);
2625 * If this file hasn't been mapped as a data file before then allocate a
2626 * section segment to describe the data file mapping
2628 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2630 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2631 TAG_MM_SECTION_SEGMENT
);
2632 if (Segment
== NULL
)
2634 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2635 ObDereferenceObject(Section
);
2636 ObDereferenceObject(FileObject
);
2637 return(STATUS_NO_MEMORY
);
2639 Section
->Segment
= Segment
;
2640 Segment
->ReferenceCount
= 1;
2641 ExInitializeFastMutex(&Segment
->Lock
);
2643 * Set the lock before assigning the segment to the file object
2645 ExAcquireFastMutex(&Segment
->Lock
);
2646 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2648 Segment
->FileOffset
= 0;
2649 Segment
->Protection
= SectionPageProtection
;
2650 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2651 Segment
->Characteristics
= 0;
2652 Segment
->WriteCopy
= FALSE
;
2653 if (AllocationAttributes
& SEC_RESERVE
)
2655 Segment
->Length
= Segment
->RawLength
= 0;
2659 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2660 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2662 Segment
->VirtualAddress
= 0;
2663 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2668 * If the file is already mapped as a data file then we may need
2672 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2674 Section
->Segment
= Segment
;
2675 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2676 MmLockSectionSegment(Segment
);
2678 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2679 !(AllocationAttributes
& SEC_RESERVE
))
2681 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2682 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2685 MmUnlockSectionSegment(Segment
);
2686 Section
->FileObject
= FileObject
;
2687 Section
->MaximumSize
= MaximumSize
;
2688 CcRosReferenceCache(FileObject
);
2689 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2690 *SectionObject
= Section
;
2691 return(STATUS_SUCCESS
);
2695 TODO: not that great (declaring loaders statically, having to declare all of
2696 them, having to keep them extern, etc.), will fix in the future
2698 extern NTSTATUS NTAPI PeFmtCreateSection
2700 IN CONST VOID
* FileHeader
,
2701 IN SIZE_T FileHeaderSize
,
2703 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2705 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2706 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2709 extern NTSTATUS NTAPI ElfFmtCreateSection
2711 IN CONST VOID
* FileHeader
,
2712 IN SIZE_T FileHeaderSize
,
2714 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2716 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2717 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2720 /* TODO: this is a standard DDK/PSDK macro */
2721 #ifndef RTL_NUMBER_OF
2722 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2725 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2736 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2738 SIZE_T SizeOfSegments
;
2739 PMM_SECTION_SEGMENT Segments
;
2741 /* TODO: check for integer overflow */
2742 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2744 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2746 TAG_MM_SECTION_SEGMENT
);
2749 RtlZeroMemory(Segments
, SizeOfSegments
);
2757 ExeFmtpReadFile(IN PVOID File
,
2758 IN PLARGE_INTEGER Offset
,
2761 OUT PVOID
* AllocBase
,
2762 OUT PULONG ReadSize
)
2765 LARGE_INTEGER FileOffset
;
2767 ULONG OffsetAdjustment
;
2772 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2776 KeBugCheck(MEMORY_MANAGEMENT
);
2779 FileOffset
= *Offset
;
2781 /* Negative/special offset: it cannot be used in this context */
2782 if(FileOffset
.u
.HighPart
< 0)
2784 KeBugCheck(MEMORY_MANAGEMENT
);
2787 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2788 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2789 FileOffset
.u
.LowPart
= AdjustOffset
;
2791 BufferSize
= Length
+ OffsetAdjustment
;
2792 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2795 * It's ok to use paged pool, because this is a temporary buffer only used in
2796 * the loading of executables. The assumption is that MmCreateSection is
2797 * always called at low IRQLs and that these buffers don't survive a brief
2798 * initialization phase
2800 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2805 KeBugCheck(MEMORY_MANAGEMENT
);
2811 Status
= MmspPageRead(File
,
2818 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2819 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2820 * to initialize internal state is even worse. Our cache manager is in need of
2824 IO_STATUS_BLOCK Iosb
;
2826 Status
= ZwReadFile(File
,
2836 if(NT_SUCCESS(Status
))
2838 UsedSize
= Iosb
.Information
;
2843 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2845 Status
= STATUS_IN_PAGE_ERROR
;
2846 ASSERT(!NT_SUCCESS(Status
));
2849 if(NT_SUCCESS(Status
))
2851 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2852 *AllocBase
= Buffer
;
2853 *ReadSize
= UsedSize
- OffsetAdjustment
;
2857 ExFreePoolWithTag(Buffer
, 'rXmM');
2864 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2865 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2866 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2871 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2875 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2877 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2878 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2885 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2889 MmspAssertSegmentsSorted(ImageSectionObject
);
2891 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2893 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2897 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2898 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2899 ImageSectionObject
->Segments
[i
- 1].Length
));
2907 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2911 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2913 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2914 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2922 MmspCompareSegments(const void * x
,
2925 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2926 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2929 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2930 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2934 * Ensures an image section's segments are sorted in memory
2939 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2942 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2944 MmspAssertSegmentsSorted(ImageSectionObject
);
2948 qsort(ImageSectionObject
->Segments
,
2949 ImageSectionObject
->NrSegments
,
2950 sizeof(ImageSectionObject
->Segments
[0]),
2951 MmspCompareSegments
);
2957 * Ensures an image section's segments don't overlap in memory and don't have
2958 * gaps and don't have a null size. We let them map to overlapping file regions,
2959 * though - that's not necessarily an error
2964 MmspCheckSegmentBounds
2966 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2972 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2974 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2978 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2980 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2982 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2990 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2991 * page could be OK (Windows seems to be OK with them), and larger gaps
2992 * could lead to image sections spanning several discontiguous regions
2993 * (NtMapViewOfSection could then refuse to map them, and they could
2994 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2996 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2997 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2998 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3009 * Merges and pads an image section's segments until they all are page-aligned
3010 * and have a size that is a multiple of the page size
3015 MmspPageAlignSegments
3017 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3023 BOOLEAN Initialized
;
3024 PMM_SECTION_SEGMENT EffectiveSegment
;
3026 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3028 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3032 Initialized
= FALSE
;
3034 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3036 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3039 * The first segment requires special handling
3043 ULONG_PTR VirtualAddress
;
3044 ULONG_PTR VirtualOffset
;
3046 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3048 /* Round down the virtual address to the nearest page */
3049 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3051 /* Round up the virtual size to the nearest page */
3052 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3053 EffectiveSegment
->VirtualAddress
;
3055 /* Adjust the raw address and size */
3056 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3058 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3064 * Garbage in, garbage out: unaligned base addresses make the file
3065 * offset point in curious and odd places, but that's what we were
3068 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3069 EffectiveSegment
->RawLength
+= VirtualOffset
;
3073 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3074 ULONG_PTR EndOfEffectiveSegment
;
3076 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3077 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3080 * The current segment begins exactly where the current effective
3081 * segment ended, therefore beginning a new effective segment
3083 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3086 ASSERT(LastSegment
<= i
);
3087 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3089 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3091 if (LastSegment
!= i
)
3094 * Copy the current segment. If necessary, the effective segment
3095 * will be expanded later
3097 *EffectiveSegment
= *Segment
;
3101 * Page-align the virtual size. We know for sure the virtual address
3104 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3105 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3108 * The current segment is still part of the current effective segment:
3109 * extend the effective segment to reflect this
3111 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3113 static const ULONG FlagsToProtection
[16] =
3121 PAGE_EXECUTE_READWRITE
,
3122 PAGE_EXECUTE_READWRITE
,
3127 PAGE_EXECUTE_WRITECOPY
,
3128 PAGE_EXECUTE_WRITECOPY
,
3129 PAGE_EXECUTE_WRITECOPY
,
3130 PAGE_EXECUTE_WRITECOPY
3133 unsigned ProtectionFlags
;
3136 * Extend the file size
3139 /* Unaligned segments must be contiguous within the file */
3140 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3141 EffectiveSegment
->RawLength
))
3146 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3149 * Extend the virtual size
3151 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3153 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3154 EffectiveSegment
->VirtualAddress
;
3157 * Merge the protection
3159 EffectiveSegment
->Protection
|= Segment
->Protection
;
3161 /* Clean up redundance */
3162 ProtectionFlags
= 0;
3164 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3165 ProtectionFlags
|= 1 << 0;
3167 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3168 ProtectionFlags
|= 1 << 1;
3170 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3171 ProtectionFlags
|= 1 << 2;
3173 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3174 ProtectionFlags
|= 1 << 3;
3176 ASSERT(ProtectionFlags
< 16);
3177 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3179 /* If a segment was required to be shared and cannot, fail */
3180 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3181 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3187 * We assume no holes between segments at this point
3191 KeBugCheck(MEMORY_MANAGEMENT
);
3195 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3201 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3202 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3204 LARGE_INTEGER Offset
;
3206 PVOID FileHeaderBuffer
;
3207 ULONG FileHeaderSize
;
3209 ULONG OldNrSegments
;
3214 * Read the beginning of the file (2 pages). Should be enough to contain
3215 * all (or most) of the headers
3217 Offset
.QuadPart
= 0;
3219 /* FIXME: use FileObject instead of FileHandle */
3220 Status
= ExeFmtpReadFile (FileHandle
,
3227 if (!NT_SUCCESS(Status
))
3230 if (FileHeaderSize
== 0)
3232 ExFreePool(FileHeaderBuffer
);
3233 return STATUS_UNSUCCESSFUL
;
3237 * Look for a loader that can handle this executable
3239 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3241 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3244 /* FIXME: use FileObject instead of FileHandle */
3245 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3251 ExeFmtpAllocateSegments
);
3253 if (!NT_SUCCESS(Status
))
3255 if (ImageSectionObject
->Segments
)
3257 ExFreePool(ImageSectionObject
->Segments
);
3258 ImageSectionObject
->Segments
= NULL
;
3262 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3266 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3269 * No loader handled the format
3271 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3273 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3274 ASSERT(!NT_SUCCESS(Status
));
3277 if (!NT_SUCCESS(Status
))
3280 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3285 /* FIXME? are these values platform-dependent? */
3286 if(ImageSectionObject
->StackReserve
== 0)
3287 ImageSectionObject
->StackReserve
= 0x40000;
3289 if(ImageSectionObject
->StackCommit
== 0)
3290 ImageSectionObject
->StackCommit
= 0x1000;
3292 if(ImageSectionObject
->ImageBase
== 0)
3294 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3295 ImageSectionObject
->ImageBase
= 0x10000000;
3297 ImageSectionObject
->ImageBase
= 0x00400000;
3301 * And now the fun part: fixing the segments
3304 /* Sort them by virtual address */
3305 MmspSortSegments(ImageSectionObject
, Flags
);
3307 /* Ensure they don't overlap in memory */
3308 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3309 return STATUS_INVALID_IMAGE_FORMAT
;
3311 /* Ensure they are aligned */
3312 OldNrSegments
= ImageSectionObject
->NrSegments
;
3314 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3315 return STATUS_INVALID_IMAGE_FORMAT
;
3317 /* Trim them if the alignment phase merged some of them */
3318 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3320 PMM_SECTION_SEGMENT Segments
;
3321 SIZE_T SizeOfSegments
;
3323 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3325 Segments
= ExAllocatePoolWithTag(PagedPool
,
3327 TAG_MM_SECTION_SEGMENT
);
3329 if (Segments
== NULL
)
3330 return STATUS_INSUFFICIENT_RESOURCES
;
3332 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3333 ExFreePool(ImageSectionObject
->Segments
);
3334 ImageSectionObject
->Segments
= Segments
;
3337 /* And finish their initialization */
3338 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3340 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3341 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3343 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3344 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3347 ASSERT(NT_SUCCESS(Status
));
3352 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3353 ACCESS_MASK DesiredAccess
,
3354 POBJECT_ATTRIBUTES ObjectAttributes
,
3355 PLARGE_INTEGER UMaximumSize
,
3356 ULONG SectionPageProtection
,
3357 ULONG AllocationAttributes
,
3360 PROS_SECTION_OBJECT Section
;
3362 PFILE_OBJECT FileObject
;
3363 PMM_SECTION_SEGMENT SectionSegments
;
3364 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3366 ULONG FileAccess
= 0;
3369 * Specifying a maximum size is meaningless for an image section
3371 if (UMaximumSize
!= NULL
)
3373 return(STATUS_INVALID_PARAMETER_4
);
3377 * Check file access required
3379 if (SectionPageProtection
& PAGE_READWRITE
||
3380 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3382 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3386 FileAccess
= FILE_READ_DATA
;
3390 * Reference the file handle
3392 Status
= ObReferenceObjectByHandle(FileHandle
,
3395 ExGetPreviousMode(),
3396 (PVOID
*)(PVOID
)&FileObject
,
3399 if (!NT_SUCCESS(Status
))
3405 * Create the section
3407 Status
= ObCreateObject (ExGetPreviousMode(),
3408 MmSectionObjectType
,
3410 ExGetPreviousMode(),
3412 sizeof(ROS_SECTION_OBJECT
),
3415 (PVOID
*)(PVOID
)&Section
);
3416 if (!NT_SUCCESS(Status
))
3418 ObDereferenceObject(FileObject
);
3425 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3426 Section
->SectionPageProtection
= SectionPageProtection
;
3427 Section
->AllocationAttributes
= AllocationAttributes
;
3430 * Initialized caching for this file object if previously caching
3431 * was initialized for the same on disk file
3433 Status
= CcTryToInitializeFileCache(FileObject
);
3435 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3437 NTSTATUS StatusExeFmt
;
3439 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3440 if (ImageSectionObject
== NULL
)
3442 ObDereferenceObject(FileObject
);
3443 ObDereferenceObject(Section
);
3444 return(STATUS_NO_MEMORY
);
3447 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3449 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3451 if (!NT_SUCCESS(StatusExeFmt
))
3453 if(ImageSectionObject
->Segments
!= NULL
)
3454 ExFreePool(ImageSectionObject
->Segments
);
3456 ExFreePool(ImageSectionObject
);
3457 ObDereferenceObject(Section
);
3458 ObDereferenceObject(FileObject
);
3459 return(StatusExeFmt
);
3462 Section
->ImageSection
= ImageSectionObject
;
3463 ASSERT(ImageSectionObject
->Segments
);
3468 Status
= MmspWaitForFileLock(FileObject
);
3469 if (!NT_SUCCESS(Status
))
3471 ExFreePool(ImageSectionObject
->Segments
);
3472 ExFreePool(ImageSectionObject
);
3473 ObDereferenceObject(Section
);
3474 ObDereferenceObject(FileObject
);
3478 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3479 ImageSectionObject
, NULL
))
3482 * An other thread has initialized the same image in the background
3484 ExFreePool(ImageSectionObject
->Segments
);
3485 ExFreePool(ImageSectionObject
);
3486 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3487 Section
->ImageSection
= ImageSectionObject
;
3488 SectionSegments
= ImageSectionObject
->Segments
;
3490 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3492 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3496 Status
= StatusExeFmt
;
3503 Status
= MmspWaitForFileLock(FileObject
);
3504 if (Status
!= STATUS_SUCCESS
)
3506 ObDereferenceObject(Section
);
3507 ObDereferenceObject(FileObject
);
3511 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3512 Section
->ImageSection
= ImageSectionObject
;
3513 SectionSegments
= ImageSectionObject
->Segments
;
3516 * Otherwise just reference all the section segments
3518 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3520 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3523 Status
= STATUS_SUCCESS
;
3525 Section
->FileObject
= FileObject
;
3526 CcRosReferenceCache(FileObject
);
3527 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3528 *SectionObject
= Section
;
3536 NtCreateSection (OUT PHANDLE SectionHandle
,
3537 IN ACCESS_MASK DesiredAccess
,
3538 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3539 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3540 IN ULONG SectionPageProtection OPTIONAL
,
3541 IN ULONG AllocationAttributes
,
3542 IN HANDLE FileHandle OPTIONAL
)
3544 LARGE_INTEGER SafeMaximumSize
;
3545 PVOID SectionObject
;
3546 KPROCESSOR_MODE PreviousMode
;
3549 PreviousMode
= ExGetPreviousMode();
3551 if(PreviousMode
!= KernelMode
)
3555 if (MaximumSize
!= NULL
)
3557 /* make a copy on the stack */
3558 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3559 MaximumSize
= &SafeMaximumSize
;
3561 ProbeForWriteHandle(SectionHandle
);
3563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3565 /* Return the exception code */
3566 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3571 Status
= MmCreateSection(&SectionObject
,
3575 SectionPageProtection
,
3576 AllocationAttributes
,
3579 if (NT_SUCCESS(Status
))
3581 Status
= ObInsertObject ((PVOID
)SectionObject
,
3593 /**********************************************************************
3611 NtOpenSection(PHANDLE SectionHandle
,
3612 ACCESS_MASK DesiredAccess
,
3613 POBJECT_ATTRIBUTES ObjectAttributes
)
3616 KPROCESSOR_MODE PreviousMode
;
3619 PreviousMode
= ExGetPreviousMode();
3621 if(PreviousMode
!= KernelMode
)
3625 ProbeForWriteHandle(SectionHandle
);
3627 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3629 /* Return the exception code */
3630 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3635 Status
= ObOpenObjectByName(ObjectAttributes
,
3636 MmSectionObjectType
,
3643 if(NT_SUCCESS(Status
))
3647 *SectionHandle
= hSection
;
3649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3651 Status
= _SEH2_GetExceptionCode();
3660 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3661 PROS_SECTION_OBJECT Section
,
3662 PMM_SECTION_SEGMENT Segment
,
3667 ULONG AllocationType
)
3671 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3673 BoundaryAddressMultiple
.QuadPart
= 0;
3675 Status
= MmCreateMemoryArea(AddressSpace
,
3676 MEMORY_AREA_SECTION_VIEW
,
3683 BoundaryAddressMultiple
);
3684 if (!NT_SUCCESS(Status
))
3686 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3687 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3691 ObReferenceObject((PVOID
)Section
);
3693 MArea
->Data
.SectionData
.Segment
= Segment
;
3694 MArea
->Data
.SectionData
.Section
= Section
;
3695 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3696 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3697 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3698 ViewSize
, 0, Protect
);
3700 return(STATUS_SUCCESS
);
3704 /**********************************************************************
3706 * NtMapViewOfSection
3709 * Maps a view of a section into the virtual address space of a
3714 * Handle of the section.
3717 * Handle of the process.
3720 * Desired base address (or NULL) on entry;
3721 * Actual base address of the view on exit.
3724 * Number of high order address bits that must be zero.
3727 * Size in bytes of the initially committed section of
3731 * Offset in bytes from the beginning of the section
3732 * to the beginning of the view.
3735 * Desired length of map (or zero to map all) on entry
3736 * Actual length mapped on exit.
3738 * InheritDisposition
3739 * Specified how the view is to be shared with
3743 * Type of allocation for the pages.
3746 * Protection for the committed region of the view.
3754 NtMapViewOfSection(IN HANDLE SectionHandle
,
3755 IN HANDLE ProcessHandle
,
3756 IN OUT PVOID
* BaseAddress OPTIONAL
,
3757 IN ULONG_PTR ZeroBits OPTIONAL
,
3758 IN SIZE_T CommitSize
,
3759 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3760 IN OUT PSIZE_T ViewSize
,
3761 IN SECTION_INHERIT InheritDisposition
,
3762 IN ULONG AllocationType OPTIONAL
,
3765 PVOID SafeBaseAddress
;
3766 LARGE_INTEGER SafeSectionOffset
;
3767 SIZE_T SafeViewSize
;
3768 PROS_SECTION_OBJECT Section
;
3770 KPROCESSOR_MODE PreviousMode
;
3771 PMMSUPPORT AddressSpace
;
3774 ACCESS_MASK DesiredAccess
;
3777 * Check the protection
3779 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3781 return STATUS_INVALID_PARAMETER_10
;
3784 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3785 if (tmpProtect
!= PAGE_NOACCESS
&&
3786 tmpProtect
!= PAGE_READONLY
&&
3787 tmpProtect
!= PAGE_READWRITE
&&
3788 tmpProtect
!= PAGE_WRITECOPY
&&
3789 tmpProtect
!= PAGE_EXECUTE
&&
3790 tmpProtect
!= PAGE_EXECUTE_READ
&&
3791 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3792 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3794 return STATUS_INVALID_PAGE_PROTECTION
;
3797 PreviousMode
= ExGetPreviousMode();
3799 if(PreviousMode
!= KernelMode
)
3801 SafeBaseAddress
= NULL
;
3802 SafeSectionOffset
.QuadPart
= 0;
3807 if(BaseAddress
!= NULL
)
3809 ProbeForWritePointer(BaseAddress
);
3810 SafeBaseAddress
= *BaseAddress
;
3812 if(SectionOffset
!= NULL
)
3814 ProbeForWriteLargeInteger(SectionOffset
);
3815 SafeSectionOffset
= *SectionOffset
;
3817 ProbeForWriteSize_t(ViewSize
);
3818 SafeViewSize
= *ViewSize
;
3820 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3822 /* Return the exception code */
3823 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3829 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3830 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3831 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3834 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3836 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3837 PROCESS_VM_OPERATION
,
3840 (PVOID
*)(PVOID
)&Process
,
3842 if (!NT_SUCCESS(Status
))
3847 AddressSpace
= &Process
->Vm
;
3849 /* Convert NT Protection Attr to Access Mask */
3850 if (Protect
== PAGE_READONLY
)
3852 DesiredAccess
= SECTION_MAP_READ
;
3854 else if (Protect
== PAGE_READWRITE
)
3856 DesiredAccess
= SECTION_MAP_WRITE
;
3858 else if (Protect
== PAGE_WRITECOPY
)
3860 DesiredAccess
= SECTION_QUERY
;
3862 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3865 DesiredAccess
= SECTION_MAP_READ
;
3868 Status
= ObReferenceObjectByHandle(SectionHandle
,
3870 MmSectionObjectType
,
3872 (PVOID
*)(PVOID
)&Section
,
3874 if (!(NT_SUCCESS(Status
)))
3876 DPRINT("ObReference failed rc=%x\n",Status
);
3877 ObDereferenceObject(Process
);
3881 Status
= MmMapViewOfSection(Section
,
3883 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3886 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3887 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3892 /* Check if this is an image for the current process */
3893 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3894 (Process
== PsGetCurrentProcess()) &&
3895 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3897 /* Notify the debugger */
3898 DbgkMapViewOfSection(Section
,
3900 SafeSectionOffset
.LowPart
,
3904 ObDereferenceObject(Section
);
3905 ObDereferenceObject(Process
);
3907 if(NT_SUCCESS(Status
))
3909 /* copy parameters back to the caller */
3912 if(BaseAddress
!= NULL
)
3914 *BaseAddress
= SafeBaseAddress
;
3916 if(SectionOffset
!= NULL
)
3918 *SectionOffset
= SafeSectionOffset
;
3920 if(ViewSize
!= NULL
)
3922 *ViewSize
= SafeViewSize
;
3925 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3927 Status
= _SEH2_GetExceptionCode();
3936 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3937 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3940 PFILE_OBJECT FileObject
;
3943 SWAPENTRY SavedSwapEntry
;
3946 PROS_SECTION_OBJECT Section
;
3947 PMM_SECTION_SEGMENT Segment
;
3948 PMMSUPPORT AddressSpace
;
3951 AddressSpace
= (PMMSUPPORT
)Context
;
3952 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3954 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3956 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3957 MemoryArea
->Data
.SectionData
.ViewOffset
;
3959 Section
= MemoryArea
->Data
.SectionData
.Section
;
3960 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3962 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3966 MmUnlockSectionSegment(Segment
);
3967 MmUnlockAddressSpace(AddressSpace
);
3969 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3970 if (Status
!= STATUS_SUCCESS
)
3972 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3973 KeBugCheck(MEMORY_MANAGEMENT
);
3976 MmLockAddressSpace(AddressSpace
);
3977 MmLockSectionSegment(Segment
);
3978 MmspCompleteAndReleasePageOp(PageOp
);
3979 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3982 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3985 * For a dirty, datafile, non-private page mark it as dirty in the
3988 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3990 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3992 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3993 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3994 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3995 ASSERT(SwapEntry
== 0);
4004 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4006 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4007 KeBugCheck(MEMORY_MANAGEMENT
);
4009 MmFreeSwapPage(SwapEntry
);
4013 if (IS_SWAP_FROM_SSE(Entry
) ||
4014 Page
!= PFN_FROM_SSE(Entry
))
4019 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4021 DPRINT1("Found a private page in a pagefile section.\n");
4022 KeBugCheck(MEMORY_MANAGEMENT
);
4025 * Just dereference private pages
4027 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4028 if (SavedSwapEntry
!= 0)
4030 MmFreeSwapPage(SavedSwapEntry
);
4031 MmSetSavedSwapEntryPage(Page
, 0);
4033 MmDeleteRmap(Page
, Process
, Address
);
4034 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4038 MmDeleteRmap(Page
, Process
, Address
);
4039 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4045 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4049 PMEMORY_AREA MemoryArea
;
4050 PROS_SECTION_OBJECT Section
;
4051 PMM_SECTION_SEGMENT Segment
;
4052 PLIST_ENTRY CurrentEntry
;
4053 PMM_REGION CurrentRegion
;
4054 PLIST_ENTRY RegionListHead
;
4056 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4058 if (MemoryArea
== NULL
)
4060 return(STATUS_UNSUCCESSFUL
);
4063 MemoryArea
->DeleteInProgress
= TRUE
;
4064 Section
= MemoryArea
->Data
.SectionData
.Section
;
4065 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4067 MmLockSectionSegment(Segment
);
4069 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4070 while (!IsListEmpty(RegionListHead
))
4072 CurrentEntry
= RemoveHeadList(RegionListHead
);
4073 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4074 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4077 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4079 Status
= MmFreeMemoryArea(AddressSpace
,
4086 Status
= MmFreeMemoryArea(AddressSpace
,
4091 MmUnlockSectionSegment(Segment
);
4092 ObDereferenceObject(Section
);
4093 return(STATUS_SUCCESS
);
4100 MmUnmapViewOfSection(PEPROCESS Process
,
4104 PMEMORY_AREA MemoryArea
;
4105 PMMSUPPORT AddressSpace
;
4106 PROS_SECTION_OBJECT Section
;
4109 PVOID ImageBaseAddress
= 0;
4111 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4112 Process
, BaseAddress
);
4116 AddressSpace
= &Process
->Vm
;
4118 MmLockAddressSpace(AddressSpace
);
4119 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4121 if (MemoryArea
== NULL
||
4122 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4123 MemoryArea
->DeleteInProgress
)
4125 MmUnlockAddressSpace(AddressSpace
);
4126 return STATUS_NOT_MAPPED_VIEW
;
4129 MemoryArea
->DeleteInProgress
= TRUE
;
4131 while (MemoryArea
->PageOpCount
)
4133 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4137 Offset
-= PAGE_SIZE
;
4138 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4139 MemoryArea
->Data
.SectionData
.Segment
,
4140 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4143 MmUnlockAddressSpace(AddressSpace
);
4144 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4145 if (Status
!= STATUS_SUCCESS
)
4147 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4148 KeBugCheck(MEMORY_MANAGEMENT
);
4150 MmLockAddressSpace(AddressSpace
);
4151 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4153 if (MemoryArea
== NULL
||
4154 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4156 MmUnlockAddressSpace(AddressSpace
);
4157 return STATUS_NOT_MAPPED_VIEW
;
4164 Section
= MemoryArea
->Data
.SectionData
.Section
;
4166 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4170 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4171 PMM_SECTION_SEGMENT SectionSegments
;
4172 PMM_SECTION_SEGMENT Segment
;
4174 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4175 ImageSectionObject
= Section
->ImageSection
;
4176 SectionSegments
= ImageSectionObject
->Segments
;
4177 NrSegments
= ImageSectionObject
->NrSegments
;
4179 /* Search for the current segment within the section segments
4180 * and calculate the image base address */
4181 for (i
= 0; i
< NrSegments
; i
++)
4183 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4185 if (Segment
== &SectionSegments
[i
])
4187 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4192 if (i
>= NrSegments
)
4194 KeBugCheck(MEMORY_MANAGEMENT
);
4197 for (i
= 0; i
< NrSegments
; i
++)
4199 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4201 PVOID SBaseAddress
= (PVOID
)
4202 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4204 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4210 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4213 MmUnlockAddressSpace(AddressSpace
);
4215 /* Notify debugger */
4216 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4218 return(STATUS_SUCCESS
);
4221 /**********************************************************************
4223 * NtUnmapViewOfSection
4238 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4242 KPROCESSOR_MODE PreviousMode
;
4245 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4246 ProcessHandle
, BaseAddress
);
4248 PreviousMode
= ExGetPreviousMode();
4250 DPRINT("Referencing process\n");
4251 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4252 PROCESS_VM_OPERATION
,
4255 (PVOID
*)(PVOID
)&Process
,
4257 if (!NT_SUCCESS(Status
))
4259 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4263 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4265 ObDereferenceObject(Process
);
4272 * Queries the information of a section object.
4274 * @param SectionHandle
4275 * Handle to the section object. It must be opened with SECTION_QUERY
4277 * @param SectionInformationClass
4278 * Index to a certain information structure. Can be either
4279 * SectionBasicInformation or SectionImageInformation. The latter
4280 * is valid only for sections that were created with the SEC_IMAGE
4282 * @param SectionInformation
4283 * Caller supplies storage for resulting information.
4285 * Size of the supplied storage.
4286 * @param ResultLength
4294 NtQuerySection(IN HANDLE SectionHandle
,
4295 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4296 OUT PVOID SectionInformation
,
4297 IN SIZE_T SectionInformationLength
,
4298 OUT PSIZE_T ResultLength OPTIONAL
)
4300 PROS_SECTION_OBJECT Section
;
4301 KPROCESSOR_MODE PreviousMode
;
4305 PreviousMode
= ExGetPreviousMode();
4307 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4309 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4311 SectionInformationLength
,
4316 if(!NT_SUCCESS(Status
))
4318 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4322 Status
= ObReferenceObjectByHandle(SectionHandle
,
4324 MmSectionObjectType
,
4326 (PVOID
*)(PVOID
)&Section
,
4328 if (NT_SUCCESS(Status
))
4330 switch (SectionInformationClass
)
4332 case SectionBasicInformation
:
4334 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4338 Sbi
->Attributes
= Section
->AllocationAttributes
;
4339 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4341 Sbi
->BaseAddress
= 0;
4342 Sbi
->Size
.QuadPart
= 0;
4346 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4347 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4350 if (ResultLength
!= NULL
)
4352 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4354 Status
= STATUS_SUCCESS
;
4356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4358 Status
= _SEH2_GetExceptionCode();
4365 case SectionImageInformation
:
4367 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4371 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4372 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4374 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4375 ImageSectionObject
= Section
->ImageSection
;
4377 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4378 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4379 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4380 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4381 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4382 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4383 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4384 Sii
->Machine
= ImageSectionObject
->Machine
;
4385 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4388 if (ResultLength
!= NULL
)
4390 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4392 Status
= STATUS_SUCCESS
;
4394 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4396 Status
= _SEH2_GetExceptionCode();
4404 ObDereferenceObject(Section
);
4412 * Extends size of file backed section.
4414 * @param SectionHandle
4415 * Handle to the section object. It must be opened with
4416 * SECTION_EXTEND_SIZE access.
4417 * @param NewMaximumSize
4418 * New maximum size of the section in bytes.
4422 * @todo Move the actual code to internal function MmExtendSection.
4426 NtExtendSection(IN HANDLE SectionHandle
,
4427 IN PLARGE_INTEGER NewMaximumSize
)
4429 LARGE_INTEGER SafeNewMaximumSize
;
4430 PROS_SECTION_OBJECT Section
;
4431 KPROCESSOR_MODE PreviousMode
;
4434 PreviousMode
= ExGetPreviousMode();
4436 if(PreviousMode
!= KernelMode
)
4440 /* make a copy on the stack */
4441 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4442 NewMaximumSize
= &SafeNewMaximumSize
;
4444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4446 /* Return the exception code */
4447 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4452 Status
= ObReferenceObjectByHandle(SectionHandle
,
4453 SECTION_EXTEND_SIZE
,
4454 MmSectionObjectType
,
4458 if (!NT_SUCCESS(Status
))
4463 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4465 ObDereferenceObject(Section
);
4466 return STATUS_INVALID_PARAMETER
;
4470 * - Acquire file extneding resource.
4471 * - Check if we're not resizing the section below it's actual size!
4472 * - Extend segments if needed.
4473 * - Set file information (FileAllocationInformation) to the new size.
4474 * - Release file extending resource.
4477 ObDereferenceObject(Section
);
4479 return STATUS_NOT_IMPLEMENTED
;
4483 /**********************************************************************
4485 * MmAllocateSection@4
4495 * Code taken from ntoskrnl/mm/special.c.
4500 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4505 PMMSUPPORT AddressSpace
;
4506 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4508 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4510 BoundaryAddressMultiple
.QuadPart
= 0;
4512 AddressSpace
= MmGetKernelAddressSpace();
4513 Result
= BaseAddress
;
4514 MmLockAddressSpace(AddressSpace
);
4515 Status
= MmCreateMemoryArea (AddressSpace
,
4523 BoundaryAddressMultiple
);
4524 MmUnlockAddressSpace(AddressSpace
);
4526 if (!NT_SUCCESS(Status
))
4530 DPRINT("Result %p\n",Result
);
4532 /* Create a virtual mapping for this memory area */
4533 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4535 return ((PVOID
)Result
);
4539 /**********************************************************************
4541 * MmMapViewOfSection
4544 * Maps a view of a section into the virtual address space of a
4549 * Pointer to the section object.
4552 * Pointer to the process.
4555 * Desired base address (or NULL) on entry;
4556 * Actual base address of the view on exit.
4559 * Number of high order address bits that must be zero.
4562 * Size in bytes of the initially committed section of
4566 * Offset in bytes from the beginning of the section
4567 * to the beginning of the view.
4570 * Desired length of map (or zero to map all) on entry
4571 * Actual length mapped on exit.
4573 * InheritDisposition
4574 * Specified how the view is to be shared with
4578 * Type of allocation for the pages.
4581 * Protection for the committed region of the view.
4589 MmMapViewOfSection(IN PVOID SectionObject
,
4590 IN PEPROCESS Process
,
4591 IN OUT PVOID
*BaseAddress
,
4592 IN ULONG_PTR ZeroBits
,
4593 IN SIZE_T CommitSize
,
4594 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4595 IN OUT PSIZE_T ViewSize
,
4596 IN SECTION_INHERIT InheritDisposition
,
4597 IN ULONG AllocationType
,
4600 PROS_SECTION_OBJECT Section
;
4601 PMMSUPPORT AddressSpace
;
4603 NTSTATUS Status
= STATUS_SUCCESS
;
4607 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4609 return STATUS_INVALID_PAGE_PROTECTION
;
4613 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4614 AddressSpace
= &Process
->Vm
;
4616 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4618 MmLockAddressSpace(AddressSpace
);
4620 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4624 ULONG_PTR ImageBase
;
4626 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4627 PMM_SECTION_SEGMENT SectionSegments
;
4629 ImageSectionObject
= Section
->ImageSection
;
4630 SectionSegments
= ImageSectionObject
->Segments
;
4631 NrSegments
= ImageSectionObject
->NrSegments
;
4634 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4637 ImageBase
= ImageSectionObject
->ImageBase
;
4641 for (i
= 0; i
< NrSegments
; i
++)
4643 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4645 ULONG_PTR MaxExtent
;
4646 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4647 SectionSegments
[i
].Length
;
4648 ImageSize
= max(ImageSize
, MaxExtent
);
4652 ImageSectionObject
->ImageSize
= ImageSize
;
4654 /* Check there is enough space to map the section at that point. */
4655 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4656 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4658 /* Fail if the user requested a fixed base address. */
4659 if ((*BaseAddress
) != NULL
)
4661 MmUnlockAddressSpace(AddressSpace
);
4662 return(STATUS_UNSUCCESSFUL
);
4664 /* Otherwise find a gap to map the image. */
4665 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4668 MmUnlockAddressSpace(AddressSpace
);
4669 return(STATUS_UNSUCCESSFUL
);
4673 for (i
= 0; i
< NrSegments
; i
++)
4675 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4677 PVOID SBaseAddress
= (PVOID
)
4678 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4679 MmLockSectionSegment(&SectionSegments
[i
]);
4680 Status
= MmMapViewOfSegment(AddressSpace
,
4682 &SectionSegments
[i
],
4684 SectionSegments
[i
].Length
,
4685 SectionSegments
[i
].Protection
,
4688 MmUnlockSectionSegment(&SectionSegments
[i
]);
4689 if (!NT_SUCCESS(Status
))
4691 MmUnlockAddressSpace(AddressSpace
);
4697 *BaseAddress
= (PVOID
)ImageBase
;
4701 /* check for write access */
4702 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4703 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4705 MmUnlockAddressSpace(AddressSpace
);
4706 return STATUS_SECTION_PROTECTION
;
4708 /* check for read access */
4709 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4710 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4712 MmUnlockAddressSpace(AddressSpace
);
4713 return STATUS_SECTION_PROTECTION
;
4715 /* check for execute access */
4716 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4717 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4719 MmUnlockAddressSpace(AddressSpace
);
4720 return STATUS_SECTION_PROTECTION
;
4723 if (ViewSize
== NULL
)
4725 /* Following this pointer would lead to us to the dark side */
4726 /* What to do? Bugcheck? Return status? Do the mambo? */
4727 KeBugCheck(MEMORY_MANAGEMENT
);
4730 if (SectionOffset
== NULL
)
4736 ViewOffset
= SectionOffset
->u
.LowPart
;
4739 if ((ViewOffset
% PAGE_SIZE
) != 0)
4741 MmUnlockAddressSpace(AddressSpace
);
4742 return(STATUS_MAPPED_ALIGNMENT
);
4745 if ((*ViewSize
) == 0)
4747 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4749 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4751 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4754 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4756 MmLockSectionSegment(Section
->Segment
);
4757 Status
= MmMapViewOfSegment(AddressSpace
,
4764 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4765 MmUnlockSectionSegment(Section
->Segment
);
4766 if (!NT_SUCCESS(Status
))
4768 MmUnlockAddressSpace(AddressSpace
);
4773 MmUnlockAddressSpace(AddressSpace
);
4775 return(STATUS_SUCCESS
);
4782 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4783 IN PLARGE_INTEGER NewFileSize
)
4785 /* Check whether an ImageSectionObject exists */
4786 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4788 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4792 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4794 PMM_SECTION_SEGMENT Segment
;
4796 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4799 if (Segment
->ReferenceCount
!= 0)
4801 /* Check size of file */
4802 if (SectionObjectPointer
->SharedCacheMap
)
4804 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4805 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4813 /* Something must gone wrong
4814 * how can we have a Section but no
4816 DPRINT("ERROR: DataSectionObject without reference!\n");
4820 DPRINT("FIXME: didn't check for outstanding write probes\n");
4830 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4840 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4841 IN MMFLUSH_TYPE FlushType
)
4845 case MmFlushForDelete
:
4846 if (SectionObjectPointer
->ImageSectionObject
||
4847 SectionObjectPointer
->DataSectionObject
)
4851 CcRosSetRemoveOnClose(SectionObjectPointer
);
4853 case MmFlushForWrite
:
4863 MmForceSectionClosed (
4864 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4865 IN BOOLEAN DelayClose
)
4876 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4877 OUT PVOID
* MappedBase
,
4878 IN OUT PSIZE_T ViewSize
)
4880 PROS_SECTION_OBJECT Section
;
4881 PMMSUPPORT AddressSpace
;
4884 DPRINT("MmMapViewInSystemSpace() called\n");
4886 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4887 AddressSpace
= MmGetKernelAddressSpace();
4889 MmLockAddressSpace(AddressSpace
);
4892 if ((*ViewSize
) == 0)
4894 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4896 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4898 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4901 MmLockSectionSegment(Section
->Segment
);
4904 Status
= MmMapViewOfSegment(AddressSpace
,
4913 MmUnlockSectionSegment(Section
->Segment
);
4914 MmUnlockAddressSpace(AddressSpace
);
4924 MmMapViewInSessionSpace (
4926 OUT PVOID
*MappedBase
,
4927 IN OUT PSIZE_T ViewSize
4931 return STATUS_NOT_IMPLEMENTED
;
4939 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4941 PMMSUPPORT AddressSpace
;
4944 DPRINT("MmUnmapViewInSystemSpace() called\n");
4946 AddressSpace
= MmGetKernelAddressSpace();
4948 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4958 MmUnmapViewInSessionSpace (
4963 return STATUS_NOT_IMPLEMENTED
;
4966 /**********************************************************************
4971 * Creates a section object.
4974 * SectionObject (OUT)
4975 * Caller supplied storage for the resulting pointer
4976 * to a SECTION_OBJECT instance;
4979 * Specifies the desired access to the section can be a
4981 * STANDARD_RIGHTS_REQUIRED |
4983 * SECTION_MAP_WRITE |
4984 * SECTION_MAP_READ |
4985 * SECTION_MAP_EXECUTE
4987 * ObjectAttributes [OPTIONAL]
4988 * Initialized attributes for the object can be used
4989 * to create a named section;
4992 * Maximizes the size of the memory section. Must be
4993 * non-NULL for a page-file backed section.
4994 * If value specified for a mapped file and the file is
4995 * not large enough, file will be extended.
4997 * SectionPageProtection
4998 * Can be a combination of:
5004 * AllocationAttributes
5005 * Can be a combination of:
5010 * Handle to a file to create a section mapped to a file
5011 * instead of a memory backed section;
5022 MmCreateSection (OUT PVOID
* Section
,
5023 IN ACCESS_MASK DesiredAccess
,
5024 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5025 IN PLARGE_INTEGER MaximumSize
,
5026 IN ULONG SectionPageProtection
,
5027 IN ULONG AllocationAttributes
,
5028 IN HANDLE FileHandle OPTIONAL
,
5029 IN PFILE_OBJECT File OPTIONAL
)
5032 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5035 * Check the protection
5037 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5038 if (Protection
!= PAGE_READONLY
&&
5039 Protection
!= PAGE_READWRITE
&&
5040 Protection
!= PAGE_WRITECOPY
&&
5041 Protection
!= PAGE_EXECUTE
&&
5042 Protection
!= PAGE_EXECUTE_READ
&&
5043 Protection
!= PAGE_EXECUTE_READWRITE
&&
5044 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5046 return STATUS_INVALID_PAGE_PROTECTION
;
5049 if (AllocationAttributes
& SEC_IMAGE
)
5051 return(MmCreateImageSection(SectionObject
,
5055 SectionPageProtection
,
5056 AllocationAttributes
,
5060 if (FileHandle
!= NULL
)
5062 return(MmCreateDataFileSection(SectionObject
,
5066 SectionPageProtection
,
5067 AllocationAttributes
,
5071 return(MmCreatePageFileSection(SectionObject
,
5075 SectionPageProtection
,
5076 AllocationAttributes
));
5081 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5082 IN PVOID File2MappedAsFile
)
5085 return STATUS_NOT_IMPLEMENTED
;