3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: section.c,v 1.138 2003/12/30 18:52:05 fireball Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/section.c
23 * PURPOSE: Implements section objects
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES *****************************************************************/
32 #define NTOS_MODE_KERNEL
34 #include <internal/mm.h>
35 #include <internal/io.h>
36 #include <internal/ob.h>
37 #include <internal/ps.h>
38 #include <internal/pool.h>
39 #include <internal/cc.h>
40 #include <ddk/ntifs.h>
41 #include <ntos/minmax.h>
42 #include <rosrtl/string.h>
43 #include <reactos/bugcodes.h>
46 #include <internal/debug.h>
48 /* TYPES *********************************************************************/
52 PSECTION_OBJECT Section
;
53 PMM_SECTION_SEGMENT Segment
;
57 } MM_SECTION_PAGEOUT_CONTEXT
;
59 /* GLOBALS *******************************************************************/
61 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
63 static GENERIC_MAPPING MmpSectionMapping
= {
64 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
65 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
66 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
69 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
70 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
72 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
73 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
74 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
75 #define MAX_SHARE_COUNT 0x7FF
76 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
77 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
78 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
80 /* FUNCTIONS *****************************************************************/
82 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
85 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
86 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
87 * RETURNS: Status of the wait.
90 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
92 LARGE_INTEGER Timeout
;
93 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
94 Timeout
.QuadPart
= -100000000LL; // 10 sec
96 Timeout
.QuadPart
= -100000000; // 10 sec
98 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
103 * FUNCTION: Sets the page op completion event and releases the page op.
104 * ARGUMENTS: PMM_PAGEOP.
105 * RETURNS: In shorter time than it takes you to even read this
106 * description, so don't even think about geting a mug of coffee.
109 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
111 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
112 MmReleasePageOp(PageOp
);
117 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
118 * ARGUMENTS: PFILE_OBJECT to wait for.
119 * RETURNS: Status of the wait.
122 MmspWaitForFileLock(PFILE_OBJECT File
)
124 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
129 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
132 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
134 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
136 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
138 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
145 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
147 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
149 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
150 PMM_SECTION_SEGMENT SectionSegments
;
154 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
155 NrSegments
= ImageSectionObject
->NrSegments
;
156 SectionSegments
= ImageSectionObject
->Segments
;
157 for (i
= 0; i
< NrSegments
; i
++)
159 if (SectionSegments
[i
].ReferenceCount
!= 0)
161 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
162 SectionSegments
[i
].ReferenceCount
);
165 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
167 ExFreePool(ImageSectionObject
);
168 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
170 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
172 PMM_SECTION_SEGMENT Segment
;
174 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
177 if (Segment
->ReferenceCount
!= 0)
179 DPRINT1("Data segment still referenced\n");
182 MmFreePageTablesSectionSegment(Segment
);
184 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
189 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
191 ExAcquireFastMutex(&Segment
->Lock
);
195 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
197 ExReleaseFastMutex(&Segment
->Lock
);
201 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
205 PSECTION_PAGE_TABLE Table
;
206 ULONG DirectoryOffset
;
209 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
211 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
215 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
216 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
220 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
221 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
222 TAG_SECTION_PAGE_TABLE
);
227 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
228 DPRINT("Table %x\n", Table
);
231 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
232 Table
->Entry
[TableOffset
] = Entry
;
237 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
240 PSECTION_PAGE_TABLE Table
;
242 ULONG DirectoryOffset
;
245 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
247 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
249 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
253 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
254 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
255 DPRINT("Table %x\n", Table
);
261 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
262 Entry
= Table
->Entry
[TableOffset
];
267 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
272 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
275 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
278 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
280 DPRINT1("Maximum share count reached\n");
283 if (IS_SWAP_FROM_SSE(Entry
))
287 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
288 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
292 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
293 PMM_SECTION_SEGMENT Segment
,
299 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
302 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
305 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
307 DPRINT1("Zero share count for unshare\n");
310 if (IS_SWAP_FROM_SSE(Entry
))
314 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
316 * If we reducing the share count of this entry to zero then set the entry
317 * to zero and tell the cache the page is no longer mapped.
319 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
321 PFILE_OBJECT FileObject
;
323 SWAPENTRY SavedSwapEntry
;
324 PHYSICAL_ADDRESS Page
;
325 BOOLEAN IsImageSection
;
328 FileOffset
= Offset
+ Segment
->FileOffset
;
330 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
332 Page
.QuadPart
= (LONGLONG
)PAGE_FROM_SSE(Entry
);
333 FileObject
= Section
->FileObject
;
334 if (FileObject
!= NULL
)
337 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
338 (FileOffset
% PAGE_SIZE
) == 0 &&
339 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
342 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
343 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
344 if (!NT_SUCCESS(Status
))
346 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
352 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
353 if (SavedSwapEntry
== 0)
355 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
359 * Try to page out this page and set the swap entry
360 * within the section segment. There exist no rmap entry
361 * for this page. The pager thread can't page out a
362 * page without a rmap entry.
364 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
365 MmReferencePage(Page
);
369 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
374 MmSetSavedSwapEntryPage(Page
, 0);
375 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
377 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
381 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
382 MmFreeSwapPage(SavedSwapEntry
);
388 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
390 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
393 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
397 PCACHE_SEGMENT CacheSeg
;
399 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
400 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
403 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
410 MiReadPage(PMEMORY_AREA MemoryArea
,
412 PHYSICAL_ADDRESS
* Page
)
414 * FUNCTION: Read a page for a section backed memory area.
416 * MemoryArea - Memory area to read the page for.
417 * Offset - Offset of the page to read.
418 * Page - Variable that receives a page contains the read data.
425 PCACHE_SEGMENT CacheSeg
;
426 PFILE_OBJECT FileObject
;
430 BOOLEAN IsImageSection
;
433 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
434 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
435 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
436 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
437 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
441 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
444 * If the file system is letting us go directly to the cache and the
445 * memory area was mapped at an offset in the file which is page aligned
446 * then get the related cache segment.
448 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
449 (FileOffset
% PAGE_SIZE
) == 0 &&
450 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
))
452 PHYSICAL_ADDRESS Addr
;
455 * Get the related cache segment; we use a lower level interface than
456 * filesystems do because it is safe for us to use an offset with a
457 * alignment less than the file system block size.
459 Status
= CcRosGetCacheSegment(Bcb
,
465 if (!NT_SUCCESS(Status
))
472 * If the cache segment isn't up to date then call the file
473 * system to read in the data.
475 Status
= ReadCacheSegment(CacheSeg
);
476 if (!NT_SUCCESS(Status
))
478 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
483 * Retrieve the page from the cache segment that we actually want.
485 Addr
= MmGetPhysicalAddress((char*)BaseAddress
+
486 FileOffset
- BaseOffset
);
488 MmReferencePage((*Page
));
490 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
495 ULONG CacheSegOffset
;
497 * Allocate a page, this is rather complicated by the possibility
498 * we might have to move other things out of memory
500 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
501 if (!NT_SUCCESS(Status
))
505 Status
= CcRosGetCacheSegment(Bcb
,
511 if (!NT_SUCCESS(Status
))
518 * If the cache segment isn't up to date then call the file
519 * system to read in the data.
521 Status
= ReadCacheSegment(CacheSeg
);
522 if (!NT_SUCCESS(Status
))
524 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
528 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
529 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
530 Length
= RawLength
- SegOffset
;
531 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
533 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
535 else if (CacheSegOffset
>= PAGE_SIZE
)
537 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
541 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
542 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
543 Status
= CcRosGetCacheSegment(Bcb
,
544 FileOffset
+ CacheSegOffset
,
549 if (!NT_SUCCESS(Status
))
551 ExUnmapPage(PageAddr
);
557 * If the cache segment isn't up to date then call the file
558 * system to read in the data.
560 Status
= ReadCacheSegment(CacheSeg
);
561 if (!NT_SUCCESS(Status
))
563 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
564 ExUnmapPage(PageAddr
);
568 if (Length
< PAGE_SIZE
)
570 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
574 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
577 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
578 ExUnmapPage(PageAddr
);
580 return(STATUS_SUCCESS
);
584 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
585 MEMORY_AREA
* MemoryArea
,
593 PSECTION_OBJECT Section
;
594 PMM_SECTION_SEGMENT Segment
;
602 * There is a window between taking the page fault and locking the
603 * address space when another thread could load the page so we check
606 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
610 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
));
612 return(STATUS_SUCCESS
);
615 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
616 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
618 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
619 Section
= MemoryArea
->Data
.SectionData
.Section
;
620 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
621 &MemoryArea
->Data
.SectionData
.RegionListHead
,
626 MmLockSectionSegment(Segment
);
629 * Check if this page needs to be mapped COW
631 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
632 (Region
->Protect
== PAGE_READWRITE
||
633 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
635 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
639 Attributes
= Region
->Protect
;
643 * Get or create a page operation descriptor
645 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
);
648 DPRINT1("MmGetPageOp failed\n");
653 * Check if someone else is already handling this fault, if so wait
656 if (PageOp
->Thread
!= PsGetCurrentThread())
658 MmUnlockSectionSegment(Segment
);
659 MmUnlockAddressSpace(AddressSpace
);
660 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
662 * Check for various strange conditions
664 if (Status
!= STATUS_SUCCESS
)
666 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
669 if (PageOp
->Status
== STATUS_PENDING
)
671 DPRINT1("Woke for page op before completion\n");
674 MmLockAddressSpace(AddressSpace
);
676 * If this wasn't a pagein then restart the operation
678 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
680 MmspCompleteAndReleasePageOp(PageOp
);
681 DPRINT("Address 0x%.8X\n", Address
);
682 return(STATUS_MM_RESTART_OPERATION
);
686 * If the thread handling this fault has failed then we don't retry
688 if (!NT_SUCCESS(PageOp
->Status
))
690 Status
= PageOp
->Status
;
691 MmspCompleteAndReleasePageOp(PageOp
);
692 DPRINT("Address 0x%.8X\n", Address
);
695 MmLockSectionSegment(Segment
);
697 * If the completed fault was for another address space then set the
700 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
702 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
705 MmUnlockSectionSegment(Segment
);
706 MmspCompleteAndReleasePageOp(PageOp
);
707 return(STATUS_MM_RESTART_OPERATION
);
710 Page
.QuadPart
= (LONGLONG
)(PAGE_FROM_SSE(Entry
));
711 MmReferencePage(Page
);
712 MmSharePageEntrySectionSegment(Segment
, Offset
);
714 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
719 if (Status
== STATUS_NO_MEMORY
)
721 MmUnlockAddressSpace(AddressSpace
);
722 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
727 MmLockAddressSpace(AddressSpace
);
730 if (!NT_SUCCESS(Status
))
732 DbgPrint("Unable to create virtual mapping\n");
735 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
741 MmUnlockSectionSegment(Segment
);
742 PageOp
->Status
= STATUS_SUCCESS
;
743 MmspCompleteAndReleasePageOp(PageOp
);
744 DPRINT("Address 0x%.8X\n", Address
);
745 return(STATUS_SUCCESS
);
749 * Must be private page we have swapped out.
751 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
))
759 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
761 DPRINT1("Found a swaped out private page in a pagefile section.\n");
765 MmUnlockSectionSegment(Segment
);
766 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
768 MmUnlockAddressSpace(AddressSpace
);
769 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
770 if (!NT_SUCCESS(Status
))
775 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
776 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
777 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
778 if (!NT_SUCCESS(Status
))
780 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
783 MmLockAddressSpace(AddressSpace
);
784 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
789 if (Status
== STATUS_NO_MEMORY
)
791 MmUnlockAddressSpace(AddressSpace
);
792 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
797 MmLockAddressSpace(AddressSpace
);
799 if (!NT_SUCCESS(Status
))
801 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
807 * Store the swap entry for later use.
809 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
812 * Add the page to the process's working set
814 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
817 * Finish the operation
821 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
823 PageOp
->Status
= STATUS_SUCCESS
;
824 MmspCompleteAndReleasePageOp(PageOp
);
825 DPRINT("Address 0x%.8X\n", Address
);
826 return(STATUS_SUCCESS
);
830 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
832 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
834 MmUnlockSectionSegment(Segment
);
836 * Just map the desired physical page
838 Page
.QuadPart
= Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
;
839 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
844 if (Status
== STATUS_NO_MEMORY
)
846 MmUnlockAddressSpace(AddressSpace
);
847 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
852 MmLockAddressSpace(AddressSpace
);
854 if (!NT_SUCCESS(Status
))
856 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
861 * Don't add an rmap entry since the page mapped could be for
870 * Cleanup and release locks
872 PageOp
->Status
= STATUS_SUCCESS
;
873 MmspCompleteAndReleasePageOp(PageOp
);
874 DPRINT("Address 0x%.8X\n", Address
);
875 return(STATUS_SUCCESS
);
879 * Map anonymous memory for BSS sections
881 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
883 MmUnlockSectionSegment(Segment
);
884 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
885 if (!NT_SUCCESS(Status
))
887 MmUnlockAddressSpace(AddressSpace
);
888 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
889 MmLockAddressSpace(AddressSpace
);
891 if (!NT_SUCCESS(Status
))
895 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
900 if (Status
== STATUS_NO_MEMORY
)
902 MmUnlockAddressSpace(AddressSpace
);
903 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
908 MmLockAddressSpace(AddressSpace
);
911 if (!NT_SUCCESS(Status
))
913 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
917 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
924 * Cleanup and release locks
926 PageOp
->Status
= STATUS_SUCCESS
;
927 MmspCompleteAndReleasePageOp(PageOp
);
928 DPRINT("Address 0x%.8X\n", Address
);
929 return(STATUS_SUCCESS
);
933 * Get the entry corresponding to the offset within the section
935 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
940 * If the entry is zero (and it can't change because we have
941 * locked the segment) then we need to load the page.
945 * Release all our locks and read in the page from disk
947 MmUnlockSectionSegment(Segment
);
948 MmUnlockAddressSpace(AddressSpace
);
950 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
951 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
953 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
954 if (!NT_SUCCESS(Status
))
956 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
961 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
962 if (!NT_SUCCESS(Status
))
964 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
967 if (!NT_SUCCESS(Status
))
970 * FIXME: What do we know in this case?
973 * Cleanup and release locks
975 MmLockAddressSpace(AddressSpace
);
976 PageOp
->Status
= Status
;
977 MmspCompleteAndReleasePageOp(PageOp
);
978 DPRINT("Address 0x%.8X\n", Address
);
982 * Relock the address space and segment
984 MmLockAddressSpace(AddressSpace
);
985 MmLockSectionSegment(Segment
);
988 * Check the entry. No one should change the status of a page
989 * that has a pending page-in.
991 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
994 DbgPrint("Someone changed ppte entry while we slept\n");
999 * Mark the offset within the section as having valid, in-memory
1002 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1003 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1004 MmUnlockSectionSegment(Segment
);
1006 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1011 if (Status
== STATUS_NO_MEMORY
)
1013 MmUnlockAddressSpace(AddressSpace
);
1014 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1019 MmLockAddressSpace(AddressSpace
);
1021 if (!NT_SUCCESS(Status
))
1023 DbgPrint("Unable to create virtual mapping\n");
1026 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1032 PageOp
->Status
= STATUS_SUCCESS
;
1033 MmspCompleteAndReleasePageOp(PageOp
);
1034 DPRINT("Address 0x%.8X\n", Address
);
1035 return(STATUS_SUCCESS
);
1037 else if (IS_SWAP_FROM_SSE(Entry
))
1039 SWAPENTRY SwapEntry
;
1042 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1045 * Release all our locks and read in the page from disk
1047 MmUnlockSectionSegment(Segment
);
1049 MmUnlockAddressSpace(AddressSpace
);
1051 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1052 if (!NT_SUCCESS(Status
))
1057 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1058 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
1059 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
1060 if (!NT_SUCCESS(Status
))
1066 * Relock the address space and segment
1068 MmLockAddressSpace(AddressSpace
);
1069 MmLockSectionSegment(Segment
);
1072 * Check the entry. No one should change the status of a page
1073 * that has a pending page-in.
1075 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1076 if (Entry
!= Entry1
)
1078 DbgPrint("Someone changed ppte entry while we slept\n");
1083 * Mark the offset within the section as having valid, in-memory
1086 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1087 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1088 MmUnlockSectionSegment(Segment
);
1091 * Save the swap entry.
1093 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1094 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1099 if (Status
== STATUS_NO_MEMORY
)
1101 MmUnlockAddressSpace(AddressSpace
);
1102 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1107 MmLockAddressSpace(AddressSpace
);
1109 if (!NT_SUCCESS(Status
))
1111 DbgPrint("Unable to create virtual mapping\n");
1114 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1119 PageOp
->Status
= STATUS_SUCCESS
;
1120 MmspCompleteAndReleasePageOp(PageOp
);
1121 DPRINT("Address 0x%.8X\n", Address
);
1122 return(STATUS_SUCCESS
);
1127 * If the section offset is already in-memory and valid then just
1128 * take another reference to the page
1131 Page
.QuadPart
= (LONGLONG
)PAGE_FROM_SSE(Entry
);
1132 MmReferencePage(Page
);
1133 MmSharePageEntrySectionSegment(Segment
, Offset
);
1134 MmUnlockSectionSegment(Segment
);
1136 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1141 if (Status
== STATUS_NO_MEMORY
)
1143 MmUnlockAddressSpace(AddressSpace
);
1144 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1149 MmLockAddressSpace(AddressSpace
);
1151 if (!NT_SUCCESS(Status
))
1153 DbgPrint("Unable to create virtual mapping\n");
1156 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1161 PageOp
->Status
= STATUS_SUCCESS
;
1162 MmspCompleteAndReleasePageOp(PageOp
);
1163 DPRINT("Address 0x%.8X\n", Address
);
1164 return(STATUS_SUCCESS
);
1169 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1170 MEMORY_AREA
* MemoryArea
,
1174 PMM_SECTION_SEGMENT Segment
;
1175 PSECTION_OBJECT Section
;
1176 PHYSICAL_ADDRESS OldPage
;
1177 PHYSICAL_ADDRESS NewPage
;
1186 * Check if the page has been paged out or has already been set readwrite
1188 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1189 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1191 DPRINT("Address 0x%.8X\n", Address
);
1192 return(STATUS_SUCCESS
);
1196 * Find the offset of the page
1198 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1199 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1201 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1202 Section
= MemoryArea
->Data
.SectionData
.Section
;
1203 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1204 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1209 MmLockSectionSegment(Segment
);
1214 if (MmGetPageEntrySectionSegment(Segment
, Offset
) == 0)
1216 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1219 MmUnlockSectionSegment(Segment
);
1221 * Check if we are doing COW
1223 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1224 (Region
->Protect
== PAGE_READWRITE
||
1225 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1227 DPRINT("Address 0x%.8X\n", Address
);
1228 return(STATUS_UNSUCCESSFUL
);
1232 * Get or create a pageop
1234 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1235 MM_PAGEOP_ACCESSFAULT
);
1238 DPRINT1("MmGetPageOp failed\n");
1243 * Wait for any other operations to complete
1245 if (PageOp
->Thread
!= PsGetCurrentThread())
1247 MmUnlockAddressSpace(AddressSpace
);
1248 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1250 * Check for various strange conditions
1252 if (Status
== STATUS_TIMEOUT
)
1254 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1257 if (PageOp
->Status
== STATUS_PENDING
)
1259 DPRINT1("Woke for page op before completion\n");
1263 * Restart the operation
1265 MmLockAddressSpace(AddressSpace
);
1266 MmspCompleteAndReleasePageOp(PageOp
);
1267 DPRINT("Address 0x%.8X\n", Address
);
1268 return(STATUS_MM_RESTART_OPERATION
);
1272 * Release locks now we have the pageop
1274 MmUnlockAddressSpace(AddressSpace
);
1279 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1280 if (!NT_SUCCESS(Status
))
1288 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1290 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1291 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1292 ExUnmapPage(NewAddress
);
1295 * Delete the old entry.
1297 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1300 * Set the PTE to point to the new page
1302 MmLockAddressSpace(AddressSpace
);
1303 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1308 if (Status
== STATUS_NO_MEMORY
)
1310 MmUnlockAddressSpace(AddressSpace
);
1311 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1316 MmLockAddressSpace(AddressSpace
);
1318 if (!NT_SUCCESS(Status
))
1320 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1324 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1325 if (!NT_SUCCESS(Status
))
1327 DbgPrint("Unable to create virtual mapping\n");
1332 /* MmUnlockPage(OldPage); */
1333 MmLockPage(NewPage
);
1337 * Unshare the old page.
1339 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1340 MmLockSectionSegment(Segment
);
1341 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
);
1342 MmUnlockSectionSegment(Segment
);
1343 MmReleasePageMemoryConsumer(MC_USER
, OldPage
);
1345 PageOp
->Status
= STATUS_SUCCESS
;
1346 MmspCompleteAndReleasePageOp(PageOp
);
1347 DPRINT("Address 0x%.8X\n", Address
);
1348 return(STATUS_SUCCESS
);
1352 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1354 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1356 PHYSICAL_ADDRESS Page
;
1358 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1359 MmDeleteVirtualMapping(Process
,
1366 PageOutContext
->WasDirty
= TRUE
;
1368 if (!PageOutContext
->Private
)
1370 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1371 PageOutContext
->Segment
,
1372 PageOutContext
->Offset
,
1373 PageOutContext
->WasDirty
);
1375 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1376 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1380 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1381 MEMORY_AREA
* MemoryArea
,
1385 PHYSICAL_ADDRESS PhysicalAddress
;
1386 MM_SECTION_PAGEOUT_CONTEXT Context
;
1387 SWAPENTRY SwapEntry
;
1392 PFILE_OBJECT FileObject
;
1394 BOOLEAN DirectMapped
;
1395 BOOLEAN IsImageSection
;
1397 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1400 * Get the segment and section.
1402 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1403 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1405 Context
.Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1406 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1408 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1410 FileObject
= Context
.Section
->FileObject
;
1411 DirectMapped
= FALSE
;
1412 if (FileObject
!= NULL
)
1414 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1417 * If the file system is letting us go directly to the cache and the
1418 * memory area was mapped at an offset in the file which is page aligned
1419 * then note this is a direct mapped page.
1421 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1422 (FileOffset
% PAGE_SIZE
) == 0 &&
1423 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1425 DirectMapped
= TRUE
;
1431 * This should never happen since mappings of physical memory are never
1432 * placed in the rmap lists.
1434 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1436 DPRINT1("Trying to page out from physical memory section address 0x%X "
1437 "process %d\n", Address
,
1438 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1443 * Get the section segment entry and the physical address.
1445 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1446 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1448 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1449 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1453 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1454 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1457 * Prepare the context structure for the rmap delete call.
1459 Context
.WasDirty
= FALSE
;
1460 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1461 IS_SWAP_FROM_SSE(Entry
) ||
1462 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1464 Context
.Private
= TRUE
;
1468 Context
.Private
= FALSE
;
1472 * Paging out data mapped read-only is easy.
1474 if (Context
.Segment
->Protection
& (PAGE_READONLY
|PAGE_EXECUTE_READ
))
1477 * Read-only data should never be in the swapfile.
1481 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1482 "paddress 0x%.8X\n", SwapEntry
, Address
,
1488 * Read-only data should never be COWed
1490 if (Context
.Private
)
1492 DPRINT1("Had private copy of read-only page.\n");
1497 * Delete all mappings of this page.
1499 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
,
1500 MmPageOutDeleteMapping
);
1501 if (Context
.WasDirty
)
1503 DPRINT1("Had a dirty page of a read-only page.\n");
1507 PageOp
->Status
= STATUS_SUCCESS
;
1508 MmspCompleteAndReleasePageOp(PageOp
);
1509 return(STATUS_SUCCESS
);
1513 * Otherwise we have read-write data.
1517 * Take an additional reference to the page or the cache segment.
1519 if (DirectMapped
&& !Context
.Private
)
1521 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1523 DPRINT1("Direct mapped non private page is not associated with the cache.\n");;
1529 MmReferencePage(PhysicalAddress
);
1532 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1535 * If this wasn't a private page then we should have reduced the entry to
1536 * zero by deleting all the rmaps.
1538 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1540 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
))
1548 * If the page wasn't dirty then we can just free it as for a readonly page.
1549 * Since we unmapped all the mappings above we know it will not suddenly
1551 * If the page is from a pagefile section and has no swap entry,
1552 * we can't free the page at this point.
1554 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1555 if (!Context
.WasDirty
&&
1556 !(SwapEntry
== 0 && Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
))
1559 if (Context
.Private
)
1561 if (!(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
) &&
1564 DPRINT1("Private page, non-dirty but not swapped out "
1565 "process %d address 0x%.8X\n",
1566 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0,
1574 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1575 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1578 if (!NT_SUCCESS(Status
))
1585 if (DirectMapped
&& !Context
.Private
)
1587 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1588 if (!NT_SUCCESS(Status
))
1590 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1596 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1599 PageOp
->Status
= STATUS_SUCCESS
;
1600 MmspCompleteAndReleasePageOp(PageOp
);
1601 return(STATUS_SUCCESS
);
1605 * If this page was direct mapped from the cache then the cache manager
1606 * will already have taken care of writing it back.
1608 if (DirectMapped
&& !Context
.Private
)
1610 assert(SwapEntry
== 0);
1611 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1612 if (!NT_SUCCESS(Status
))
1614 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
1617 PageOp
->Status
= STATUS_SUCCESS
;
1618 MmspCompleteAndReleasePageOp(PageOp
);
1619 return(STATUS_SUCCESS
);
1623 * If necessary, allocate an entry in the paging file for this page
1627 SwapEntry
= MmAllocSwapPage();
1630 MmShowOutOfSpaceMessagePagingFile();
1633 * For private pages restore the old mappings.
1635 if (Context
.Private
)
1637 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1639 MemoryArea
->Attributes
,
1642 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1643 MmInsertRmap(PhysicalAddress
,
1644 MemoryArea
->Process
,
1650 * For non-private pages if the page wasn't direct mapped then
1651 * set it back into the section segment entry so we don't loose
1652 * our copy. Otherwise it will be handled by the cache manager.
1654 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1656 MemoryArea
->Attributes
,
1659 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1660 MmInsertRmap(PhysicalAddress
,
1661 MemoryArea
->Process
,
1663 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1664 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1666 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1667 MmspCompleteAndReleasePageOp(PageOp
);
1668 return(STATUS_PAGEFILE_QUOTA
);
1673 * Write the page to the pagefile
1675 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1676 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1677 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1678 if (!NT_SUCCESS(Status
))
1680 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1683 * As above: undo our actions.
1684 * FIXME: Also free the swap page.
1686 if (Context
.Private
)
1688 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1690 MemoryArea
->Attributes
,
1693 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1694 MmInsertRmap(PhysicalAddress
,
1695 MemoryArea
->Process
,
1700 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1702 MemoryArea
->Attributes
,
1705 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1706 MmInsertRmap(PhysicalAddress
,
1707 MemoryArea
->Process
,
1709 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1710 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1712 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1713 MmspCompleteAndReleasePageOp(PageOp
);
1714 return(STATUS_UNSUCCESSFUL
);
1718 * Otherwise we have succeeded.
1720 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1721 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1722 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1724 if (Context
.Private
)
1726 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1729 if (!NT_SUCCESS(Status
))
1736 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1737 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1740 PageOp
->Status
= STATUS_SUCCESS
;
1741 MmspCompleteAndReleasePageOp(PageOp
);
1742 return(STATUS_SUCCESS
);
1746 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1747 PMEMORY_AREA MemoryArea
,
1752 PSECTION_OBJECT Section
;
1753 PMM_SECTION_SEGMENT Segment
;
1754 PHYSICAL_ADDRESS PhysicalAddress
;
1755 SWAPENTRY SwapEntry
;
1760 PFILE_OBJECT FileObject
;
1762 BOOLEAN DirectMapped
;
1763 BOOLEAN IsImageSection
;
1765 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1767 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1770 * Get the segment and section.
1772 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1773 Section
= MemoryArea
->Data
.SectionData
.Section
;
1774 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1776 FileObject
= Section
->FileObject
;
1777 DirectMapped
= FALSE
;
1778 if (FileObject
!= NULL
)
1780 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1783 * If the file system is letting us go directly to the cache and the
1784 * memory area was mapped at an offset in the file which is page aligned
1785 * then note this is a direct mapped page.
1787 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1788 (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1789 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1791 DirectMapped
= TRUE
;
1796 * This should never happen since mappings of physical memory are never
1797 * placed in the rmap lists.
1799 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1801 DPRINT1("Trying to write back page from physical memory mapped at %X "
1802 "process %d\n", Address
,
1803 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1808 * Get the section segment entry and the physical address.
1810 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1811 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1813 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1814 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1818 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1819 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1822 * Check for a private (COWed) page.
1824 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1825 IS_SWAP_FROM_SSE(Entry
) ||
1826 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1836 * Speculatively set all mappings of the page to clean.
1838 MmSetCleanAllRmaps(PhysicalAddress
);
1841 * If this page was direct mapped from the cache then the cache manager
1842 * will take care of writing it back to disk.
1844 if (DirectMapped
&& !Private
)
1846 assert(SwapEntry
== 0);
1847 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1848 PageOp
->Status
= STATUS_SUCCESS
;
1849 MmspCompleteAndReleasePageOp(PageOp
);
1850 return(STATUS_SUCCESS
);
1854 * If necessary, allocate an entry in the paging file for this page
1858 SwapEntry
= MmAllocSwapPage();
1861 MmSetDirtyAllRmaps(PhysicalAddress
);
1862 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1863 MmspCompleteAndReleasePageOp(PageOp
);
1864 return(STATUS_PAGEFILE_QUOTA
);
1866 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
1870 * Write the page to the pagefile
1872 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1873 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1874 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1875 if (!NT_SUCCESS(Status
))
1877 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1879 MmSetDirtyAllRmaps(PhysicalAddress
);
1880 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1881 MmspCompleteAndReleasePageOp(PageOp
);
1882 return(STATUS_UNSUCCESSFUL
);
1886 * Otherwise we have succeeded.
1888 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1889 PageOp
->Status
= STATUS_SUCCESS
;
1890 MmspCompleteAndReleasePageOp(PageOp
);
1891 return(STATUS_SUCCESS
);
1895 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1903 PMEMORY_AREA MemoryArea
;
1904 PMM_SECTION_SEGMENT Segment
;
1908 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1909 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1911 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1912 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1917 if (OldProtect
!= NewProtect
)
1919 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1921 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1922 ULONG Protect
= NewProtect
;
1925 * If we doing COW for this segment then check if the page is
1928 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1932 LARGE_INTEGER PhysicalAddress
;
1934 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1935 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1937 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1939 Protect
= PAGE_READONLY
;
1940 if ((Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1941 IS_SWAP_FROM_SSE(Entry
) ||
1942 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
))
1944 Protect
= NewProtect
;
1948 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1950 MmSetPageProtect(AddressSpace
->Process
, BaseAddress
,
1958 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1959 PMEMORY_AREA MemoryArea
,
1969 min(Length
, (ULONG
) ((char*)MemoryArea
->BaseAddress
+ MemoryArea
->Length
- (char*)BaseAddress
));
1970 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1971 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1973 *OldProtect
= Region
->Protect
;
1974 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
1975 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1976 BaseAddress
, Length
, Region
->Type
, Protect
,
1977 MmAlterViewAttributes
);
1983 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1985 PMEMORY_BASIC_INFORMATION Info
,
1986 PULONG ResultLength
)
1989 PVOID RegionBaseAddress
;
1991 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1992 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1993 Address
, &RegionBaseAddress
);
1996 return STATUS_UNSUCCESSFUL
;
1998 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1999 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
2000 Info
->AllocationProtect
= MemoryArea
->Attributes
;
2001 Info
->RegionSize
= MemoryArea
->Length
;
2002 Info
->State
= MEM_COMMIT
;
2003 Info
->Protect
= Region
->Protect
;
2004 if (MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
)
2006 Info
->Type
= MEM_IMAGE
;
2010 Info
->Type
= MEM_MAPPED
;
2013 return(STATUS_SUCCESS
);
2017 MmpDeleteSection(PVOID ObjectBody
)
2019 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2021 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2022 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2026 PMM_SECTION_SEGMENT SectionSegments
;
2028 SectionSegments
= Section
->ImageSection
->Segments
;
2029 NrSegments
= Section
->ImageSection
->NrSegments
;
2031 for (i
= 0; i
< NrSegments
; i
++)
2033 InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2038 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2043 PMM_SECTION_SEGMENT Segment
;
2045 Segment
= Section
->Segment
;
2046 Length
= PAGE_ROUND_UP(Segment
->Length
);
2048 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2050 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2053 if (IS_SWAP_FROM_SSE(Entry
))
2055 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2059 PHYSICAL_ADDRESS Page
;
2060 Page
.QuadPart
= (LONGLONG
)PAGE_FROM_SSE(Entry
);
2061 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2065 MmFreePageTablesSectionSegment(Section
->Segment
);
2066 ExFreePool(Section
->Segment
);
2067 Section
->Segment
= NULL
;
2071 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2074 if (Section
->FileObject
!= NULL
)
2076 CcRosDereferenceCache(Section
->FileObject
);
2077 ObDereferenceObject(Section
->FileObject
);
2078 Section
->FileObject
= NULL
;
2083 MmpCloseSection(PVOID ObjectBody
,
2086 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2087 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2091 MmpCreateSection(PVOID ObjectBody
,
2093 PWSTR RemainingPath
,
2094 POBJECT_ATTRIBUTES ObjectAttributes
)
2096 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2097 ObjectBody
, Parent
, RemainingPath
);
2099 if (RemainingPath
== NULL
)
2101 return(STATUS_SUCCESS
);
2104 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2106 return(STATUS_UNSUCCESSFUL
);
2108 return(STATUS_SUCCESS
);
2111 NTSTATUS INIT_FUNCTION
2112 MmCreatePhysicalMemorySection(VOID
)
2114 HANDLE PhysSectionH
;
2115 PSECTION_OBJECT PhysSection
;
2117 OBJECT_ATTRIBUTES Obj
;
2118 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2119 LARGE_INTEGER SectionSize
;
2122 * Create the section mapping physical memory
2124 SectionSize
.QuadPart
= 0xFFFFFFFF;
2125 InitializeObjectAttributes(&Obj
,
2130 Status
= NtCreateSection(&PhysSectionH
,
2134 PAGE_EXECUTE_READWRITE
,
2137 if (!NT_SUCCESS(Status
))
2139 DbgPrint("Failed to create PhysicalMemory section\n");
2142 Status
= ObReferenceObjectByHandle(PhysSectionH
,
2146 (PVOID
*)&PhysSection
,
2148 if (!NT_SUCCESS(Status
))
2150 DbgPrint("Failed to reference PhysicalMemory section\n");
2153 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2154 ObDereferenceObject((PVOID
)PhysSection
);
2156 return(STATUS_SUCCESS
);
2159 NTSTATUS INIT_FUNCTION
2160 MmInitSectionImplementation(VOID
)
2162 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2164 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2166 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2167 MmSectionObjectType
->TotalObjects
= 0;
2168 MmSectionObjectType
->TotalHandles
= 0;
2169 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2170 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2171 MmSectionObjectType
->PagedPoolCharge
= 0;
2172 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2173 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2174 MmSectionObjectType
->Dump
= NULL
;
2175 MmSectionObjectType
->Open
= NULL
;
2176 MmSectionObjectType
->Close
= MmpCloseSection
;
2177 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2178 MmSectionObjectType
->Parse
= NULL
;
2179 MmSectionObjectType
->Security
= NULL
;
2180 MmSectionObjectType
->QueryName
= NULL
;
2181 MmSectionObjectType
->OkayToClose
= NULL
;
2182 MmSectionObjectType
->Create
= MmpCreateSection
;
2183 MmSectionObjectType
->DuplicationNotify
= NULL
;
2186 * NOTE: Do not register the section object type here because
2187 * the object manager it not initialized yet!
2188 * The section object type will be created in ObInit().
2190 ObpCreateTypeObject(MmSectionObjectType
);
2192 return(STATUS_SUCCESS
);
2196 MmCreatePageFileSection(PHANDLE SectionHandle
,
2197 ACCESS_MASK DesiredAccess
,
2198 POBJECT_ATTRIBUTES ObjectAttributes
,
2199 PLARGE_INTEGER UMaximumSize
,
2200 ULONG SectionPageProtection
,
2201 ULONG AllocationAttributes
)
2203 * Create a section which is backed by the pagefile
2206 LARGE_INTEGER MaximumSize
;
2207 PSECTION_OBJECT Section
;
2208 PMM_SECTION_SEGMENT Segment
;
2211 if (UMaximumSize
== NULL
)
2213 return(STATUS_UNSUCCESSFUL
);
2215 MaximumSize
= *UMaximumSize
;
2218 * Check the protection
2220 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2221 SectionPageProtection
)
2223 return(STATUS_INVALID_PAGE_PROTECTION
);
2227 * Create the section
2229 Status
= ObCreateObject(ExGetPreviousMode(),
2230 MmSectionObjectType
,
2232 ExGetPreviousMode(),
2234 sizeof(SECTION_OBJECT
),
2238 if (!NT_SUCCESS(Status
))
2243 Status
= ObInsertObject ((PVOID
)Section
,
2249 if (!NT_SUCCESS(Status
))
2251 ObDereferenceObject(Section
);
2258 Section
->SectionPageProtection
= SectionPageProtection
;
2259 Section
->AllocationAttributes
= AllocationAttributes
;
2260 InitializeListHead(&Section
->ViewListHead
);
2261 KeInitializeSpinLock(&Section
->ViewListLock
);
2262 Section
->FileObject
= NULL
;
2263 Section
->MaximumSize
= MaximumSize
;
2264 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2265 TAG_MM_SECTION_SEGMENT
);
2266 if (Segment
== NULL
)
2268 ZwClose(*SectionHandle
);
2269 ObDereferenceObject(Section
);
2270 return(STATUS_NO_MEMORY
);
2272 Section
->Segment
= Segment
;
2273 Segment
->ReferenceCount
= 1;
2274 ExInitializeFastMutex(&Segment
->Lock
);
2275 Segment
->FileOffset
= 0;
2276 Segment
->Protection
= SectionPageProtection
;
2277 Segment
->Attributes
= AllocationAttributes
;
2278 Segment
->Length
= MaximumSize
.u
.LowPart
;
2279 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2280 Segment
->WriteCopy
= FALSE
;
2281 ObDereferenceObject(Section
);
2282 return(STATUS_SUCCESS
);
2287 MmCreateDataFileSection(PHANDLE SectionHandle
,
2288 ACCESS_MASK DesiredAccess
,
2289 POBJECT_ATTRIBUTES ObjectAttributes
,
2290 PLARGE_INTEGER UMaximumSize
,
2291 ULONG SectionPageProtection
,
2292 ULONG AllocationAttributes
,
2295 * Create a section backed by a data file
2298 PSECTION_OBJECT Section
;
2300 LARGE_INTEGER MaximumSize
;
2301 PFILE_OBJECT FileObject
;
2302 PMM_SECTION_SEGMENT Segment
;
2304 IO_STATUS_BLOCK Iosb
;
2305 LARGE_INTEGER Offset
;
2309 * Check the protection
2311 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2312 SectionPageProtection
)
2314 return(STATUS_INVALID_PAGE_PROTECTION
);
2317 * Create the section
2319 Status
= ObCreateObject(ExGetPreviousMode(),
2320 MmSectionObjectType
,
2322 ExGetPreviousMode(),
2324 sizeof(SECTION_OBJECT
),
2328 if (!NT_SUCCESS(Status
))
2333 Status
= ObInsertObject ((PVOID
)Section
,
2339 if (!NT_SUCCESS(Status
))
2341 ObDereferenceObject(Section
);
2348 Section
->SectionPageProtection
= SectionPageProtection
;
2349 Section
->AllocationAttributes
= AllocationAttributes
;
2350 InitializeListHead(&Section
->ViewListHead
);
2351 KeInitializeSpinLock(&Section
->ViewListLock
);
2354 * Check file access required
2356 if (SectionPageProtection
& PAGE_READWRITE
||
2357 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2359 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2363 FileAccess
= FILE_READ_DATA
;
2367 * Reference the file handle
2369 Status
= ObReferenceObjectByHandle(FileHandle
,
2373 (PVOID
*)&FileObject
,
2375 if (!NT_SUCCESS(Status
))
2377 ZwClose(*SectionHandle
);
2378 ObDereferenceObject(Section
);
2383 * We can't do memory mappings if the file system doesn't support the
2386 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2388 ZwClose(*SectionHandle
);
2389 ObDereferenceObject(Section
);
2390 ObDereferenceObject(FileObject
);
2391 return(STATUS_INVALID_FILE_FOR_SECTION
);
2395 * FIXME: Revise this once a locking order for file size changes is
2398 if (UMaximumSize
!= NULL
)
2400 MaximumSize
= *UMaximumSize
;
2405 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2408 if (MaximumSize
.QuadPart
>
2409 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2411 Status
= NtSetInformationFile(FileHandle
,
2414 sizeof(LARGE_INTEGER
),
2415 FileAllocationInformation
);
2416 if (!NT_SUCCESS(Status
))
2418 ZwClose(*SectionHandle
);
2419 ObDereferenceObject(Section
);
2420 ObDereferenceObject(FileObject
);
2421 return(STATUS_SECTION_NOT_EXTENDED
);
2425 if (FileObject
->SectionObjectPointer
== NULL
||
2426 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2429 * Read a bit so caching is initiated for the file object.
2430 * This is only needed because MiReadPage currently cannot
2431 * handle non-cached streams.
2433 Offset
.QuadPart
= 0;
2434 Status
= ZwReadFile(FileHandle
,
2443 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2445 ZwClose(*SectionHandle
);
2446 ObDereferenceObject(Section
);
2447 ObDereferenceObject(FileObject
);
2450 if (FileObject
->SectionObjectPointer
== NULL
||
2451 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2453 /* FIXME: handle this situation */
2454 ZwClose(*SectionHandle
);
2455 ObDereferenceObject(Section
);
2456 ObDereferenceObject(FileObject
);
2457 return STATUS_INVALID_PARAMETER
;
2464 Status
= MmspWaitForFileLock(FileObject
);
2465 if (Status
!= STATUS_SUCCESS
)
2467 ZwClose(*SectionHandle
);
2468 ObDereferenceObject(Section
);
2469 ObDereferenceObject(FileObject
);
2474 * If this file hasn't been mapped as a data file before then allocate a
2475 * section segment to describe the data file mapping
2477 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2479 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2480 TAG_MM_SECTION_SEGMENT
);
2481 if (Segment
== NULL
)
2483 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2484 ZwClose(*SectionHandle
);
2485 ObDereferenceObject(Section
);
2486 ObDereferenceObject(FileObject
);
2487 return(STATUS_NO_MEMORY
);
2489 Section
->Segment
= Segment
;
2490 Segment
->ReferenceCount
= 1;
2491 ExInitializeFastMutex(&Segment
->Lock
);
2493 * Set the lock before assigning the segment to the file object
2495 ExAcquireFastMutex(&Segment
->Lock
);
2496 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2498 Segment
->FileOffset
= 0;
2499 Segment
->Protection
= 0;
2500 Segment
->Attributes
= 0;
2501 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2502 Segment
->Characteristics
= 0;
2503 Segment
->WriteCopy
= FALSE
;
2504 if (AllocationAttributes
& SEC_RESERVE
)
2506 Segment
->Length
= Segment
->RawLength
= 0;
2510 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2511 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2513 Segment
->VirtualAddress
= NULL
;
2518 * If the file is already mapped as a data file then we may need
2522 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2524 Section
->Segment
= Segment
;
2525 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2526 MmLockSectionSegment(Segment
);
2528 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2529 !(AllocationAttributes
& SEC_RESERVE
))
2531 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2532 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2535 MmUnlockSectionSegment(Segment
);
2536 Section
->FileObject
= FileObject
;
2537 Section
->MaximumSize
= MaximumSize
;
2538 CcRosReferenceCache(FileObject
);
2539 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2540 ObDereferenceObject(Section
);
2541 return(STATUS_SUCCESS
);
2544 static ULONG SectionCharacteristicsToProtect
[16] =
2546 PAGE_NOACCESS
, // 0 = NONE
2547 PAGE_NOACCESS
, // 1 = SHARED
2548 PAGE_EXECUTE
, // 2 = EXECUTABLE
2549 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2550 PAGE_READONLY
, // 4 = READABLE
2551 PAGE_READONLY
, // 5 = READABLE, SHARED
2552 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2553 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2554 PAGE_READWRITE
, // 8 = WRITABLE
2555 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2556 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2557 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2558 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2559 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2560 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2561 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2565 MmCreateImageSection(PHANDLE SectionHandle
,
2566 ACCESS_MASK DesiredAccess
,
2567 POBJECT_ATTRIBUTES ObjectAttributes
,
2568 PLARGE_INTEGER UMaximumSize
,
2569 ULONG SectionPageProtection
,
2570 ULONG AllocationAttributes
,
2573 PSECTION_OBJECT Section
;
2575 PFILE_OBJECT FileObject
;
2576 IMAGE_DOS_HEADER DosHeader
;
2577 IO_STATUS_BLOCK Iosb
;
2578 LARGE_INTEGER Offset
;
2579 IMAGE_NT_HEADERS PEHeader
;
2580 PMM_SECTION_SEGMENT SectionSegments
;
2582 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2585 ULONG Characteristics
;
2586 ULONG FileAccess
= 0;
2588 * Check the protection
2590 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2591 SectionPageProtection
)
2593 return(STATUS_INVALID_PAGE_PROTECTION
);
2597 * Specifying a maximum size is meaningless for an image section
2599 if (UMaximumSize
!= NULL
)
2601 return(STATUS_INVALID_PARAMETER_4
);
2605 * Reference the file handle
2607 Status
= ObReferenceObjectByHandle(FileHandle
,
2611 (PVOID
*)&FileObject
,
2613 if (!NT_SUCCESS(Status
))
2619 * Initialized caching for this file object if previously caching
2620 * was initialized for the same on disk file
2622 Status
= CcTryToInitializeFileCache(FileObject
);
2624 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2626 PIMAGE_SECTION_HEADER ImageSections
;
2628 * Read the dos header and check the DOS signature
2630 Offset
.QuadPart
= 0;
2631 Status
= ZwReadFile(FileHandle
,
2640 if (!NT_SUCCESS(Status
))
2642 ObDereferenceObject(FileObject
);
2647 * Check the DOS signature
2649 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2650 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2652 ObDereferenceObject(FileObject
);
2653 return(STATUS_INVALID_IMAGE_FORMAT
);
2657 * Read the PE header
2659 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2660 Status
= ZwReadFile(FileHandle
,
2669 if (!NT_SUCCESS(Status
))
2671 ObDereferenceObject(FileObject
);
2676 * Check the signature
2678 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2679 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2681 ObDereferenceObject(FileObject
);
2682 return(STATUS_INVALID_IMAGE_FORMAT
);
2686 * Read in the section headers
2688 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2689 ImageSections
= ExAllocatePool(NonPagedPool
,
2690 PEHeader
.FileHeader
.NumberOfSections
*
2691 sizeof(IMAGE_SECTION_HEADER
));
2692 if (ImageSections
== NULL
)
2694 ObDereferenceObject(FileObject
);
2695 return(STATUS_NO_MEMORY
);
2698 Status
= ZwReadFile(FileHandle
,
2704 PEHeader
.FileHeader
.NumberOfSections
*
2705 sizeof(IMAGE_SECTION_HEADER
),
2708 if (!NT_SUCCESS(Status
))
2710 ObDereferenceObject(FileObject
);
2711 ExFreePool(ImageSections
);
2714 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2716 ObDereferenceObject(FileObject
);
2717 ExFreePool(ImageSections
);
2718 return(STATUS_INVALID_IMAGE_FORMAT
);
2722 * Create the section
2724 Status
= ObCreateObject (ExGetPreviousMode(),
2725 MmSectionObjectType
,
2727 ExGetPreviousMode(),
2729 sizeof(SECTION_OBJECT
),
2733 if (!NT_SUCCESS(Status
))
2735 ObDereferenceObject(FileObject
);
2736 ExFreePool(ImageSections
);
2740 Status
= ObInsertObject ((PVOID
)Section
,
2746 if (!NT_SUCCESS(Status
))
2748 ObDereferenceObject(Section
);
2749 ObDereferenceObject(FileObject
);
2750 ExFreePool(ImageSections
);
2757 Section
->SectionPageProtection
= SectionPageProtection
;
2758 Section
->AllocationAttributes
= AllocationAttributes
;
2759 InitializeListHead(&Section
->ViewListHead
);
2760 KeInitializeSpinLock(&Section
->ViewListLock
);
2763 * Check file access required
2765 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2767 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2771 FileAccess
= FILE_READ_DATA
;
2775 * We can't do memory mappings if the file system doesn't support the
2778 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2780 ZwClose(*SectionHandle
);
2781 ObDereferenceObject(Section
);
2782 ObDereferenceObject(FileObject
);
2783 ExFreePool(ImageSections
);
2784 return(STATUS_INVALID_FILE_FOR_SECTION
);
2790 Status
= MmspWaitForFileLock(FileObject
);
2791 if (Status
!= STATUS_SUCCESS
)
2793 ZwClose(*SectionHandle
);
2794 ObDereferenceObject(Section
);
2795 ObDereferenceObject(FileObject
);
2796 ExFreePool(ImageSections
);
2801 * allocate the section segments to describe the mapping
2803 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2804 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2805 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2806 if (ImageSectionObject
== NULL
)
2808 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2809 ZwClose(*SectionHandle
);
2810 ObDereferenceObject(Section
);
2811 ObDereferenceObject(FileObject
);
2812 ExFreePool(ImageSections
);
2813 return(STATUS_NO_MEMORY
);
2815 Section
->ImageSection
= ImageSectionObject
;
2816 ImageSectionObject
->NrSegments
= NrSegments
;
2817 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2818 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2819 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2820 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2821 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2822 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2823 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2824 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2825 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2826 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2828 SectionSegments
= ImageSectionObject
->Segments
;
2829 SectionSegments
[0].FileOffset
= 0;
2830 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2831 SectionSegments
[0].Protection
= PAGE_READONLY
;
2832 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2833 SectionSegments
[0].Length
= PAGE_SIZE
;
2834 SectionSegments
[0].Flags
= 0;
2835 SectionSegments
[0].ReferenceCount
= 1;
2836 SectionSegments
[0].VirtualAddress
= 0;
2837 SectionSegments
[0].WriteCopy
= FALSE
;
2838 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2839 for (i
= 1; i
< NrSegments
; i
++)
2841 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2842 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2845 * Set up the protection and write copy variables.
2847 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2848 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2850 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2851 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2853 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2855 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2856 SectionSegments
[i
].WriteCopy
= TRUE
;
2858 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2860 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2861 SectionSegments
[i
].WriteCopy
= TRUE
;
2863 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2865 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2866 SectionSegments
[i
].WriteCopy
= TRUE
;
2870 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2871 SectionSegments
[i
].WriteCopy
= TRUE
;
2875 * Set up the attributes.
2877 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2879 SectionSegments
[i
].Attributes
= 0;
2881 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2883 SectionSegments
[i
].Attributes
= 0;
2885 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2887 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2891 SectionSegments
[i
].Attributes
= 0;
2894 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2895 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2896 SectionSegments
[i
].Flags
= 0;
2897 SectionSegments
[i
].ReferenceCount
= 1;
2898 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2899 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2901 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2902 (LONG
)ImageSectionObject
, 0))
2905 * An other thread has initialized the some image in the background
2907 ExFreePool(ImageSectionObject
);
2908 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2909 Section
->ImageSection
= ImageSectionObject
;
2910 SectionSegments
= ImageSectionObject
->Segments
;
2912 for (i
= 0; i
< NrSegments
; i
++)
2914 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2917 ExFreePool(ImageSections
);
2922 * Create the section
2924 Status
= ObCreateObject (ExGetPreviousMode(),
2925 MmSectionObjectType
,
2927 ExGetPreviousMode(),
2929 sizeof(SECTION_OBJECT
),
2933 if (!NT_SUCCESS(Status
))
2935 ObDereferenceObject(FileObject
);
2939 Status
= ObInsertObject ((PVOID
)Section
,
2945 if (!NT_SUCCESS(Status
))
2947 ObDereferenceObject(Section
);
2948 ObDereferenceObject(FileObject
);
2955 Section
->SectionPageProtection
= SectionPageProtection
;
2956 Section
->AllocationAttributes
= AllocationAttributes
;
2957 InitializeListHead(&Section
->ViewListHead
);
2958 KeInitializeSpinLock(&Section
->ViewListLock
);
2961 * Check file access required
2963 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2965 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2969 FileAccess
= FILE_READ_DATA
;
2975 Status
= MmspWaitForFileLock(FileObject
);
2976 if (Status
!= STATUS_SUCCESS
)
2978 ZwClose(*SectionHandle
);
2979 ObDereferenceObject(Section
);
2980 ObDereferenceObject(FileObject
);
2984 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2985 Section
->ImageSection
= ImageSectionObject
;
2986 SectionSegments
= ImageSectionObject
->Segments
;
2987 NrSegments
= ImageSectionObject
->NrSegments
;
2990 * Otherwise just reference all the section segments
2992 for (i
= 0; i
< NrSegments
; i
++)
2994 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2998 Section
->FileObject
= FileObject
;
2999 CcRosReferenceCache(FileObject
);
3000 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3001 ObDereferenceObject(Section
);
3002 return(STATUS_SUCCESS
);
3009 NtCreateSection (OUT PHANDLE SectionHandle
,
3010 IN ACCESS_MASK DesiredAccess
,
3011 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3012 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3013 IN ULONG SectionPageProtection OPTIONAL
,
3014 IN ULONG AllocationAttributes
,
3015 IN HANDLE FileHandle OPTIONAL
)
3017 if (AllocationAttributes
& SEC_IMAGE
)
3019 return(MmCreateImageSection(SectionHandle
,
3023 SectionPageProtection
,
3024 AllocationAttributes
,
3028 if (FileHandle
!= NULL
)
3030 return(MmCreateDataFileSection(SectionHandle
,
3034 SectionPageProtection
,
3035 AllocationAttributes
,
3039 return(MmCreatePageFileSection(SectionHandle
,
3043 SectionPageProtection
,
3044 AllocationAttributes
));
3048 /**********************************************************************
3066 NtOpenSection(PHANDLE SectionHandle
,
3067 ACCESS_MASK DesiredAccess
,
3068 POBJECT_ATTRIBUTES ObjectAttributes
)
3074 Status
= ObOpenObjectByName(ObjectAttributes
,
3075 MmSectionObjectType
,
3086 MmMapViewOfSegment(PEPROCESS Process
,
3087 PMADDRESS_SPACE AddressSpace
,
3088 PSECTION_OBJECT Section
,
3089 PMM_SECTION_SEGMENT Segment
,
3100 Status
= MmCreateMemoryArea(Process
,
3102 MEMORY_AREA_SECTION_VIEW
,
3109 if (!NT_SUCCESS(Status
))
3111 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3112 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
);
3116 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3117 InsertTailList(&Section
->ViewListHead
,
3118 &MArea
->Data
.SectionData
.ViewListEntry
);
3119 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3121 ObReferenceObjectByPointer((PVOID
)Section
,
3124 ExGetPreviousMode());
3125 MArea
->Data
.SectionData
.Segment
= Segment
;
3126 MArea
->Data
.SectionData
.Section
= Section
;
3127 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3128 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3129 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3130 ViewSize
, 0, Protect
);
3132 return(STATUS_SUCCESS
);
3136 /**********************************************************************
3138 * NtMapViewOfSection
3141 * Maps a view of a section into the virtual address space of a
3146 * Handle of the section.
3149 * Handle of the process.
3152 * Desired base address (or NULL) on entry;
3153 * Actual base address of the view on exit.
3156 * Number of high order address bits that must be zero.
3159 * Size in bytes of the initially committed section of
3163 * Offset in bytes from the beginning of the section
3164 * to the beginning of the view.
3167 * Desired length of map (or zero to map all) on entry
3168 * Actual length mapped on exit.
3170 * InheritDisposition
3171 * Specified how the view is to be shared with
3175 * Type of allocation for the pages.
3178 * Protection for the committed region of the view.
3186 NtMapViewOfSection(HANDLE SectionHandle
,
3187 HANDLE ProcessHandle
,
3191 PLARGE_INTEGER SectionOffset
,
3193 SECTION_INHERIT InheritDisposition
,
3194 ULONG AllocationType
,
3197 PSECTION_OBJECT Section
;
3200 PMADDRESS_SPACE AddressSpace
;
3202 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3203 PROCESS_VM_OPERATION
,
3208 if (!NT_SUCCESS(Status
))
3213 AddressSpace
= &Process
->AddressSpace
;
3215 Status
= ObReferenceObjectByHandle(SectionHandle
,
3217 MmSectionObjectType
,
3221 if (!(NT_SUCCESS(Status
)))
3223 DPRINT("ObReference failed rc=%x\n",Status
);
3224 ObDereferenceObject(Process
);
3228 Status
= MmMapViewOfSection(Section
,
3239 ObDereferenceObject(Section
);
3240 ObDereferenceObject(Process
);
3246 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3247 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
3252 PFILE_OBJECT FileObject
;
3255 SWAPENTRY SavedSwapEntry
;
3258 PSECTION_OBJECT Section
;
3259 PMM_SECTION_SEGMENT Segment
;
3261 MArea
= (PMEMORY_AREA
)Context
;
3263 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3265 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3267 Section
= MArea
->Data
.SectionData
.Section
;
3268 Segment
= MArea
->Data
.SectionData
.Segment
;
3271 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3275 MmUnlockSectionSegment(Segment
);
3276 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3278 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3279 if (Status
!= STATUS_SUCCESS
)
3281 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3285 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3286 MmLockSectionSegment(Segment
);
3287 MmspCompleteAndReleasePageOp(PageOp
);
3288 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3291 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3294 * For a dirty, datafile, non-private page mark it as dirty in the
3297 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3299 if (PhysAddr
.QuadPart
== PAGE_FROM_SSE(Entry
) && Dirty
)
3301 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3302 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3303 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3304 assert(SwapEntry
== 0);
3313 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3315 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3318 MmFreeSwapPage(SwapEntry
);
3320 else if (PhysAddr
.QuadPart
!= 0)
3322 if (IS_SWAP_FROM_SSE(Entry
) ||
3323 PhysAddr
.QuadPart
!= (PAGE_FROM_SSE(Entry
)))
3328 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3330 DPRINT1("Found a private page in a pagefile section.\n");
3334 * Just dereference private pages
3336 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysAddr
);
3337 if (SavedSwapEntry
!= 0)
3339 MmFreeSwapPage(SavedSwapEntry
);
3340 MmSetSavedSwapEntryPage(PhysAddr
, 0);
3342 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3343 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3347 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3348 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
);
3349 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3355 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3359 PMEMORY_AREA MemoryArea
;
3360 PSECTION_OBJECT Section
;
3361 PMM_SECTION_SEGMENT Segment
;
3363 PLIST_ENTRY CurrentEntry
;
3364 PMM_REGION CurrentRegion
;
3365 PLIST_ENTRY RegionListHead
;
3367 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3369 if (MemoryArea
== NULL
)
3371 return(STATUS_UNSUCCESSFUL
);
3374 MemoryArea
->DeleteInProgress
= TRUE
;
3375 Section
= MemoryArea
->Data
.SectionData
.Section
;
3376 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3378 MmLockSectionSegment(Segment
);
3379 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3380 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3381 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3383 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3384 while (!IsListEmpty(RegionListHead
))
3386 CurrentEntry
= RemoveHeadList(RegionListHead
);
3387 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3388 ExFreePool(CurrentRegion
);
3391 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3393 Status
= MmFreeMemoryArea(AddressSpace
,
3401 Status
= MmFreeMemoryArea(AddressSpace
,
3407 MmUnlockSectionSegment(Segment
);
3408 ObDereferenceObject(Section
);
3409 return(STATUS_SUCCESS
);
3416 MmUnmapViewOfSection(PEPROCESS Process
,
3420 PMEMORY_AREA MemoryArea
;
3421 PMADDRESS_SPACE AddressSpace
;
3422 PSECTION_OBJECT Section
;
3424 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3425 Process
, BaseAddress
);
3429 AddressSpace
= &Process
->AddressSpace
;
3430 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3432 if (MemoryArea
== NULL
)
3434 return(STATUS_UNSUCCESSFUL
);
3437 Section
= MemoryArea
->Data
.SectionData
.Section
;
3439 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3443 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3444 PMM_SECTION_SEGMENT SectionSegments
;
3445 PVOID ImageBaseAddress
= 0;
3446 PMM_SECTION_SEGMENT Segment
;
3448 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3449 ImageSectionObject
= Section
->ImageSection
;
3450 SectionSegments
= ImageSectionObject
->Segments
;
3451 NrSegments
= ImageSectionObject
->NrSegments
;
3453 /* Search for the current segment within the section segments
3454 * and calculate the image base address */
3455 for (i
= 0; i
< NrSegments
; i
++)
3457 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3459 if (Segment
== &SectionSegments
[i
])
3461 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3466 if (i
>= NrSegments
)
3471 for (i
= 0; i
< NrSegments
; i
++)
3473 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3475 PVOID SBaseAddress
= (PVOID
)
3476 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3478 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3484 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3486 return(STATUS_SUCCESS
);
3489 /**********************************************************************
3491 * NtUnmapViewOfSection
3506 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3512 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3513 ProcessHandle
, BaseAddress
);
3515 DPRINT("Referencing process\n");
3516 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3517 PROCESS_VM_OPERATION
,
3522 if (!NT_SUCCESS(Status
))
3524 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3528 MmLockAddressSpace(&Process
->AddressSpace
);
3529 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3530 MmUnlockAddressSpace(&Process
->AddressSpace
);
3532 ObDereferenceObject(Process
);
3539 NtQuerySection (IN HANDLE SectionHandle
,
3540 IN CINT SectionInformationClass
,
3541 OUT PVOID SectionInformation
,
3543 OUT PULONG ResultLength
)
3545 * FUNCTION: Queries the information of a section object.
3547 * SectionHandle = Handle to the section link object
3548 * SectionInformationClass = Index to a certain information structure
3549 * SectionInformation (OUT)= Caller supplies storage for resulting
3551 * Length = Size of the supplied storage
3552 * ResultLength = Data written
3557 PSECTION_OBJECT Section
;
3560 Status
= ObReferenceObjectByHandle(SectionHandle
,
3562 MmSectionObjectType
,
3566 if (!(NT_SUCCESS(Status
)))
3571 switch (SectionInformationClass
)
3573 case SectionBasicInformation
:
3575 PSECTION_BASIC_INFORMATION Sbi
;
3577 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3579 ObDereferenceObject(Section
);
3580 return(STATUS_INFO_LENGTH_MISMATCH
);
3583 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3585 Sbi
->BaseAddress
= 0;
3586 Sbi
->Attributes
= 0;
3587 Sbi
->Size
.QuadPart
= 0;
3589 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3590 Status
= STATUS_SUCCESS
;
3594 case SectionImageInformation
:
3596 PSECTION_IMAGE_INFORMATION Sii
;
3598 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3600 ObDereferenceObject(Section
);
3601 return(STATUS_INFO_LENGTH_MISMATCH
);
3604 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3605 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3606 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3608 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3609 ImageSectionObject
= Section
->ImageSection
;
3611 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3612 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3613 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3614 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3615 Sii
->MinorSubsystemVersion
= (USHORT
)ImageSectionObject
->MinorSubsystemVersion
;
3616 Sii
->MajorSubsystemVersion
= (USHORT
)ImageSectionObject
->MajorSubsystemVersion
;
3617 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3618 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3619 Sii
->Executable
= ImageSectionObject
->Executable
;
3621 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3622 Status
= STATUS_SUCCESS
;
3628 Status
= STATUS_INVALID_INFO_CLASS
;
3630 ObDereferenceObject(Section
);
3636 NtExtendSection(IN HANDLE SectionHandle
,
3637 IN ULONG NewMaximumSize
)
3640 return(STATUS_NOT_IMPLEMENTED
);
3644 /**********************************************************************
3646 * MmAllocateSection@4
3656 * Code taken from ntoskrnl/mm/special.c.
3661 MmAllocateSection (IN ULONG Length
)
3667 PMADDRESS_SPACE AddressSpace
;
3669 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3671 AddressSpace
= MmGetKernelAddressSpace();
3673 MmLockAddressSpace(AddressSpace
);
3674 Status
= MmCreateMemoryArea (NULL
,
3683 MmUnlockAddressSpace(AddressSpace
);
3684 if (!NT_SUCCESS(Status
))
3688 DPRINT("Result %p\n",Result
);
3689 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3691 PHYSICAL_ADDRESS Page
;
3693 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3694 if (!NT_SUCCESS(Status
))
3696 DbgPrint("Unable to allocate page\n");
3699 Status
= MmCreateVirtualMapping (NULL
,
3700 ((char*)Result
+ (i
* PAGE_SIZE
)),
3704 if (!NT_SUCCESS(Status
))
3706 DbgPrint("Unable to create virtual mapping\n");
3710 return ((PVOID
)Result
);
3714 /**********************************************************************
3716 * MmMapViewOfSection
3719 * Maps a view of a section into the virtual address space of a
3724 * Pointer to the section object.
3727 * Pointer to the process.
3730 * Desired base address (or NULL) on entry;
3731 * Actual base address of the view on exit.
3734 * Number of high order address bits that must be zero.
3737 * Size in bytes of the initially committed section of
3741 * Offset in bytes from the beginning of the section
3742 * to the beginning of the view.
3745 * Desired length of map (or zero to map all) on entry
3746 * Actual length mapped on exit.
3748 * InheritDisposition
3749 * Specified how the view is to be shared with
3753 * Type of allocation for the pages.
3756 * Protection for the committed region of the view.
3764 MmMapViewOfSection(IN PVOID SectionObject
,
3765 IN PEPROCESS Process
,
3766 IN OUT PVOID
*BaseAddress
,
3768 IN ULONG CommitSize
,
3769 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3770 IN OUT PULONG ViewSize
,
3771 IN SECTION_INHERIT InheritDisposition
,
3772 IN ULONG AllocationType
,
3775 PSECTION_OBJECT Section
;
3776 PMADDRESS_SPACE AddressSpace
;
3778 NTSTATUS Status
= STATUS_SUCCESS
;
3782 Section
= (PSECTION_OBJECT
)SectionObject
;
3783 AddressSpace
= &Process
->AddressSpace
;
3785 MmLockAddressSpace(AddressSpace
);
3787 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3793 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3794 PMM_SECTION_SEGMENT SectionSegments
;
3796 ImageSectionObject
= Section
->ImageSection
;
3797 SectionSegments
= ImageSectionObject
->Segments
;
3798 NrSegments
= ImageSectionObject
->NrSegments
;
3801 ImageBase
= *BaseAddress
;
3802 if (ImageBase
== NULL
)
3804 ImageBase
= ImageSectionObject
->ImageBase
;
3808 for (i
= 0; i
< NrSegments
; i
++)
3810 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3813 MaxExtent
= (ULONG
)((char*)SectionSegments
[i
].VirtualAddress
+
3814 SectionSegments
[i
].Length
);
3815 ImageSize
= max(ImageSize
, MaxExtent
);
3819 /* Check there is enough space to map the section at that point. */
3820 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3821 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3823 /* Fail if the user requested a fixed base address. */
3824 if ((*BaseAddress
) != NULL
)
3826 MmUnlockAddressSpace(AddressSpace
);
3827 return(STATUS_UNSUCCESSFUL
);
3829 /* Otherwise find a gap to map the image. */
3830 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3831 if (ImageBase
== NULL
)
3833 MmUnlockAddressSpace(AddressSpace
);
3834 return(STATUS_UNSUCCESSFUL
);
3838 for (i
= 0; i
< NrSegments
; i
++)
3840 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3842 PVOID SBaseAddress
= (PVOID
)
3843 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3844 MmLockSectionSegment(&SectionSegments
[i
]);
3845 Status
= MmMapViewOfSegment(Process
,
3848 &SectionSegments
[i
],
3850 SectionSegments
[i
].Length
,
3851 SectionSegments
[i
].Protection
,
3852 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3854 MmUnlockSectionSegment(&SectionSegments
[i
]);
3855 if (!NT_SUCCESS(Status
))
3857 MmUnlockAddressSpace(AddressSpace
);
3863 *BaseAddress
= ImageBase
;
3867 if (ViewSize
== NULL
)
3869 /* Following this pointer would lead to us to the dark side */
3870 /* What to do? Bugcheck? Return status? Do the mambo? */
3871 KEBUGCHECK(MEMORY_MANAGEMENT
);
3874 if (SectionOffset
== NULL
)
3880 ViewOffset
= SectionOffset
->u
.LowPart
;
3883 if ((ViewOffset
% PAGE_SIZE
) != 0)
3885 MmUnlockAddressSpace(AddressSpace
);
3886 return(STATUS_MAPPED_ALIGNMENT
);
3889 if ((*ViewSize
) == 0)
3891 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3893 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3895 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3898 MmLockSectionSegment(Section
->Segment
);
3899 Status
= MmMapViewOfSegment(Process
,
3907 (AllocationType
& MEM_TOP_DOWN
));
3908 MmUnlockSectionSegment(Section
->Segment
);
3909 if (!NT_SUCCESS(Status
))
3911 MmUnlockAddressSpace(AddressSpace
);
3916 MmUnlockAddressSpace(AddressSpace
);
3918 return(STATUS_SUCCESS
);
3925 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3926 IN PLARGE_INTEGER NewFileSize
)
3937 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
3947 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3948 IN MMFLUSH_TYPE FlushType
)
3952 case MmFlushForDelete
:
3953 if (SectionObjectPointer
->ImageSectionObject
||
3954 SectionObjectPointer
->DataSectionObject
)
3958 CcRosSetRemoveOnClose(SectionObjectPointer
);
3960 case MmFlushForWrite
:
3970 MmForceSectionClosed (DWORD Unknown0
,
3982 MmMapViewInSystemSpace (IN PVOID SectionObject
,
3983 OUT PVOID
* MappedBase
,
3984 IN OUT PULONG ViewSize
)
3986 PSECTION_OBJECT Section
;
3987 PMADDRESS_SPACE AddressSpace
;
3990 DPRINT("MmMapViewInSystemSpace() called\n");
3992 Section
= (PSECTION_OBJECT
)SectionObject
;
3993 AddressSpace
= MmGetKernelAddressSpace();
3995 MmLockAddressSpace(AddressSpace
);
3998 if ((*ViewSize
) == 0)
4000 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4002 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4004 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4007 MmLockSectionSegment(Section
->Segment
);
4010 Status
= MmMapViewOfSegment(NULL
,
4020 MmUnlockSectionSegment(Section
->Segment
);
4021 MmUnlockAddressSpace(AddressSpace
);
4031 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4033 PMADDRESS_SPACE AddressSpace
;
4036 DPRINT("MmUnmapViewInSystemSpace() called\n");
4038 AddressSpace
= MmGetKernelAddressSpace();
4040 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4050 MmSetBankedSection (DWORD Unknown0
,
4058 return (STATUS_NOT_IMPLEMENTED
);
4062 /**********************************************************************
4067 * Creates a section object.
4070 * SectionObjiect (OUT)
4071 * Caller supplied storage for the resulting pointer
4072 * to a SECTION_OBJECT instance;
4075 * Specifies the desired access to the section can be a
4077 * STANDARD_RIGHTS_REQUIRED |
4079 * SECTION_MAP_WRITE |
4080 * SECTION_MAP_READ |
4081 * SECTION_MAP_EXECUTE
4083 * ObjectAttributes [OPTIONAL]
4084 * Initialized attributes for the object can be used
4085 * to create a named section;
4088 * Maximizes the size of the memory section. Must be
4089 * non-NULL for a page-file backed section.
4090 * If value specified for a mapped file and the file is
4091 * not large enough, file will be extended.
4093 * SectionPageProtection
4094 * Can be a combination of:
4100 * AllocationAttributes
4101 * Can be a combination of:
4106 * Handle to a file to create a section mapped to a file
4107 * instead of a memory backed section;
4118 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4119 IN ACCESS_MASK DesiredAccess
,
4120 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4121 IN PLARGE_INTEGER MaximumSize
,
4122 IN ULONG SectionPageProtection
,
4123 IN ULONG AllocationAttributes
,
4124 IN HANDLE FileHandle OPTIONAL
,
4125 IN PFILE_OBJECT File OPTIONAL
)
4127 return (STATUS_NOT_IMPLEMENTED
);