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.121 2003/07/11 01:23:15 royce 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/ps.h>
37 #include <internal/pool.h>
38 #include <internal/cc.h>
39 #include <ddk/ntifs.h>
40 #include <ntos/minmax.h>
43 #include <internal/debug.h>
45 /* TYPES *********************************************************************/
49 PSECTION_OBJECT Section
;
50 PMM_SECTION_SEGMENT Segment
;
54 } MM_SECTION_PAGEOUT_CONTEXT
;
56 /* GLOBALS *******************************************************************/
58 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
60 static GENERIC_MAPPING MmpSectionMapping
= {
61 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
62 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
63 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
66 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
67 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
69 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
70 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
71 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
72 #define MAX_SHARE_COUNT 0x7FF
73 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
74 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
75 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
77 /* FUNCTIONS *****************************************************************/
80 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
83 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
85 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
87 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
89 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
96 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
98 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
100 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
101 PMM_SECTION_SEGMENT SectionSegments
;
105 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
106 NrSegments
= ImageSectionObject
->NrSegments
;
107 SectionSegments
= ImageSectionObject
->Segments
;
108 for (i
= 0; i
< NrSegments
; i
++)
110 if (SectionSegments
[i
].ReferenceCount
!= 0)
112 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
113 SectionSegments
[i
].ReferenceCount
);
116 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
118 ExFreePool(ImageSectionObject
);
119 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
121 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
123 PMM_SECTION_SEGMENT Segment
;
125 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
128 if (Segment
->ReferenceCount
!= 0)
130 DPRINT1("Data segment still referenced\n");
133 MmFreePageTablesSectionSegment(Segment
);
135 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
140 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
142 ExAcquireFastMutex(&Segment
->Lock
);
146 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
148 ExReleaseFastMutex(&Segment
->Lock
);
152 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
156 PSECTION_PAGE_TABLE Table
;
157 ULONG DirectoryOffset
;
160 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
162 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
166 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
167 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
171 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
172 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
173 TAG_SECTION_PAGE_TABLE
);
178 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
179 DPRINT("Table %x\n", Table
);
182 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
183 Table
->Entry
[TableOffset
] = Entry
;
188 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
191 PSECTION_PAGE_TABLE Table
;
193 ULONG DirectoryOffset
;
196 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
198 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
200 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
204 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
205 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
206 DPRINT("Table %x\n", Table
);
212 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
213 Entry
= Table
->Entry
[TableOffset
];
218 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
223 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
226 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
229 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
231 DPRINT1("Maximum share count reached\n");
234 if (IS_SWAP_FROM_SSE(Entry
))
238 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
239 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
243 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
244 PMM_SECTION_SEGMENT Segment
,
250 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
253 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
256 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
258 DPRINT1("Zero share count for unshare\n");
261 if (IS_SWAP_FROM_SSE(Entry
))
265 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
267 * If we reducing the share count of this entry to zero then set the entry
268 * to zero and tell the cache the page is no longer mapped.
270 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
272 PFILE_OBJECT FileObject
;
274 SWAPENTRY SavedSwapEntry
;
275 PHYSICAL_ADDRESS Page
;
276 BOOLEAN IsImageSection
;
279 FileOffset
= Offset
+ Segment
->FileOffset
;
281 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
283 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
284 Page
= (PHYSICAL_ADDRESS
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
285 FileObject
= Section
->FileObject
;
286 if (FileObject
!= NULL
)
289 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
290 (FileOffset
% PAGE_SIZE
) == 0 &&
291 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
294 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
295 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
296 if (!NT_SUCCESS(Status
))
298 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
304 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
305 if (SavedSwapEntry
!= 0)
307 MmFreeSwapPage(SavedSwapEntry
);
308 MmSetSavedSwapEntryPage(Page
, 0);
313 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
315 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
318 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
322 PCACHE_SEGMENT CacheSeg
;
324 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
325 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
328 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
335 MiReadPage(PMEMORY_AREA MemoryArea
,
337 PHYSICAL_ADDRESS
* Page
)
339 * FUNCTION: Read a page for a section backed memory area.
341 * MemoryArea - Memory area to read the page for.
342 * Offset - Offset of the page to read.
343 * Page - Variable that receives a page contains the read data.
350 PCACHE_SEGMENT CacheSeg
;
351 PFILE_OBJECT FileObject
;
355 BOOLEAN IsImageSection
;
358 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
359 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
360 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
361 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
362 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
366 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
369 * If the file system is letting us go directly to the cache and the
370 * memory area was mapped at an offset in the file which is page aligned
371 * then get the related cache segment.
373 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
374 (FileOffset
% PAGE_SIZE
) == 0 &&
375 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
))
377 PHYSICAL_ADDRESS Addr
;
380 * Get the related cache segment; we use a lower level interface than
381 * filesystems do because it is safe for us to use an offset with a
382 * alignment less than the file system block size.
384 Status
= CcRosGetCacheSegment(Bcb
,
390 if (!NT_SUCCESS(Status
))
397 * If the cache segment isn't up to date then call the file
398 * system to read in the data.
400 Status
= ReadCacheSegment(CacheSeg
);
401 if (!NT_SUCCESS(Status
))
403 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
408 * Retrieve the page from the cache segment that we actually want.
410 Addr
= MmGetPhysicalAddress(BaseAddress
+
411 FileOffset
- BaseOffset
);
413 MmReferencePage((*Page
));
415 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
420 ULONG CacheSegOffset
;
422 * Allocate a page, this is rather complicated by the possibility
423 * we might have to move other things out of memory
425 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
426 if (!NT_SUCCESS(Status
))
430 Status
= CcRosGetCacheSegment(Bcb
,
436 if (!NT_SUCCESS(Status
))
443 * If the cache segment isn't up to date then call the file
444 * system to read in the data.
446 Status
= ReadCacheSegment(CacheSeg
);
447 if (!NT_SUCCESS(Status
))
449 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
453 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
454 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
455 Length
= RawLength
- SegOffset
;
456 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
458 memcpy(PageAddr
, BaseAddress
+ FileOffset
- BaseOffset
, Length
);
460 else if (CacheSegOffset
>= PAGE_SIZE
)
462 memcpy(PageAddr
, BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
466 memcpy(PageAddr
, BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
467 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
468 Status
= CcRosGetCacheSegment(Bcb
,
469 FileOffset
+ CacheSegOffset
,
474 if (!NT_SUCCESS(Status
))
476 ExUnmapPage(PageAddr
);
482 * If the cache segment isn't up to date then call the file
483 * system to read in the data.
485 Status
= ReadCacheSegment(CacheSeg
);
486 if (!NT_SUCCESS(Status
))
488 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
489 ExUnmapPage(PageAddr
);
493 if (Length
< PAGE_SIZE
)
495 memcpy(PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
499 memcpy(PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
502 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
503 ExUnmapPage(PageAddr
);
505 return(STATUS_SUCCESS
);
509 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
510 MEMORY_AREA
* MemoryArea
,
518 PSECTION_OBJECT Section
;
519 PMM_SECTION_SEGMENT Segment
;
525 LARGE_INTEGER Timeout
;
528 * There is a window between taking the page fault and locking the
529 * address space when another thread could load the page so we check
532 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
536 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
));
538 return(STATUS_SUCCESS
);
541 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
542 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
544 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
545 Section
= MemoryArea
->Data
.SectionData
.Section
;
546 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
547 &MemoryArea
->Data
.SectionData
.RegionListHead
,
552 MmLockSectionSegment(Segment
);
555 * Check if this page needs to be mapped COW
557 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
558 (Region
->Protect
== PAGE_READWRITE
||
559 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
561 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
565 Attributes
= Region
->Protect
;
569 * Get or create a page operation descriptor
571 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
);
574 DPRINT1("MmGetPageOp failed\n");
579 * Check if someone else is already handling this fault, if so wait
582 if (PageOp
->Thread
!= PsGetCurrentThread())
584 MmUnlockSectionSegment(Segment
);
585 MmUnlockAddressSpace(AddressSpace
);
586 Timeout
.QuadPart
= -100000000LL; // 10 sec
587 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
594 * Check for various strange conditions
596 if (Status
!= STATUS_SUCCESS
)
598 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
601 if (PageOp
->Status
== STATUS_PENDING
)
603 DPRINT1("Woke for page op before completion\n");
606 MmLockAddressSpace(AddressSpace
);
608 * If this wasn't a pagein then restart the operation
610 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
612 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
613 MmReleasePageOp(PageOp
);
614 DPRINT("Address 0x%.8X\n", Address
);
615 return(STATUS_MM_RESTART_OPERATION
);
619 * If the thread handling this fault has failed then we don't retry
621 if (!NT_SUCCESS(PageOp
->Status
))
623 Status
= PageOp
->Status
;
624 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
625 MmReleasePageOp(PageOp
);
626 DPRINT("Address 0x%.8X\n", Address
);
629 MmLockSectionSegment(Segment
);
631 * If the completed fault was for another address space then set the
634 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
636 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
639 MmUnlockSectionSegment(Segment
);
640 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
641 MmReleasePageOp(PageOp
);
642 return(STATUS_MM_RESTART_OPERATION
);
645 Page
= (LARGE_INTEGER
)(LONGLONG
)(PAGE_FROM_SSE(Entry
));
646 MmReferencePage(Page
);
647 MmSharePageEntrySectionSegment(Segment
, Offset
);
649 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
654 if (Status
== STATUS_NO_MEMORY
)
656 MmUnlockAddressSpace(AddressSpace
);
657 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
662 MmLockAddressSpace(AddressSpace
);
665 if (!NT_SUCCESS(Status
))
667 DbgPrint("Unable to create virtual mapping\n");
670 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
676 MmUnlockSectionSegment(Segment
);
677 PageOp
->Status
= STATUS_SUCCESS
;
678 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
679 MmReleasePageOp(PageOp
);
680 DPRINT("Address 0x%.8X\n", Address
);
681 return(STATUS_SUCCESS
);
685 * Must be private page we have swapped out.
687 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
))
692 MmUnlockSectionSegment(Segment
);
693 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
695 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
696 if (!NT_SUCCESS(Status
))
701 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
702 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
703 MmUnlockAddressSpace(AddressSpace
);
704 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
705 if (!NT_SUCCESS(Status
))
707 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
710 MmLockAddressSpace(AddressSpace
);
711 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
716 if (Status
== STATUS_NO_MEMORY
)
718 MmUnlockAddressSpace(AddressSpace
);
719 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
724 MmLockAddressSpace(AddressSpace
);
726 if (!NT_SUCCESS(Status
))
728 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
734 * Store the swap entry for later use.
736 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
739 * Add the page to the process's working set
741 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
744 * Finish the operation
748 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
750 PageOp
->Status
= STATUS_SUCCESS
;
751 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
752 MmReleasePageOp(PageOp
);
753 DPRINT("Address 0x%.8X\n", Address
);
754 return(STATUS_SUCCESS
);
758 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
760 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
762 MmUnlockSectionSegment(Segment
);
764 * Just map the desired physical page
766 Page
.QuadPart
= Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
;
767 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
772 if (Status
== STATUS_NO_MEMORY
)
774 MmUnlockAddressSpace(AddressSpace
);
775 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
780 MmLockAddressSpace(AddressSpace
);
782 if (!NT_SUCCESS(Status
))
784 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
789 * Don't add an rmap entry since the page mapped could be for
798 * Cleanup and release locks
800 PageOp
->Status
= STATUS_SUCCESS
;
801 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
802 MmReleasePageOp(PageOp
);
803 DPRINT("Address 0x%.8X\n", Address
);
804 return(STATUS_SUCCESS
);
808 * Map anonymous memory for BSS sections
810 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
812 MmUnlockSectionSegment(Segment
);
813 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
814 if (!NT_SUCCESS(Status
))
816 MmUnlockAddressSpace(AddressSpace
);
817 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
818 MmLockAddressSpace(AddressSpace
);
820 if (!NT_SUCCESS(Status
))
824 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
829 if (Status
== STATUS_NO_MEMORY
)
831 MmUnlockAddressSpace(AddressSpace
);
832 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
837 MmLockAddressSpace(AddressSpace
);
840 if (!NT_SUCCESS(Status
))
842 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
846 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
853 * Cleanup and release locks
855 PageOp
->Status
= STATUS_SUCCESS
;
856 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
857 MmReleasePageOp(PageOp
);
858 DPRINT("Address 0x%.8X\n", Address
);
859 return(STATUS_SUCCESS
);
863 * Get the entry corresponding to the offset within the section
865 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
870 * If the entry is zero (and it can't change because we have
871 * locked the segment) then we need to load the page.
875 * Release all our locks and read in the page from disk
877 MmUnlockSectionSegment(Segment
);
878 MmUnlockAddressSpace(AddressSpace
);
880 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
881 (Offset
> Segment
->RawLength
&& Section
->AllocationAttributes
& SEC_IMAGE
))
883 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
887 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
889 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
892 * FIXME: What do we know in this case?
894 DPRINT1("MiReadPage or MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
896 * Cleanup and release locks
898 MmLockAddressSpace(AddressSpace
);
899 PageOp
->Status
= Status
;
900 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
901 MmReleasePageOp(PageOp
);
902 DPRINT("Address 0x%.8X\n", Address
);
906 * Relock the address space and segment
908 MmLockAddressSpace(AddressSpace
);
909 MmLockSectionSegment(Segment
);
912 * Check the entry. No one should change the status of a page
913 * that has a pending page-in.
915 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
918 DbgPrint("Someone changed ppte entry while we slept\n");
923 * Mark the offset within the section as having valid, in-memory
926 Entry
= Page
.u
.LowPart
;
927 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
928 MmSharePageEntrySectionSegment(Segment
, Offset
);
929 MmUnlockSectionSegment(Segment
);
931 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
936 if (Status
== STATUS_NO_MEMORY
)
938 MmUnlockAddressSpace(AddressSpace
);
939 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
944 MmLockAddressSpace(AddressSpace
);
946 if (!NT_SUCCESS(Status
))
948 DbgPrint("Unable to create virtual mapping\n");
951 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
957 PageOp
->Status
= STATUS_SUCCESS
;
958 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
959 MmReleasePageOp(PageOp
);
960 DPRINT("Address 0x%.8X\n", Address
);
961 return(STATUS_SUCCESS
);
963 else if (IS_SWAP_FROM_SSE(Entry
))
968 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
971 * Release all our locks and read in the page from disk
973 MmUnlockSectionSegment(Segment
);
975 MmUnlockAddressSpace(AddressSpace
);
977 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
978 if (!NT_SUCCESS(Status
))
983 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
984 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
985 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
986 if (!NT_SUCCESS(Status
))
992 * Relock the address space and segment
994 MmLockAddressSpace(AddressSpace
);
995 MmLockSectionSegment(Segment
);
998 * Check the entry. No one should change the status of a page
999 * that has a pending page-in.
1001 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1002 if (Entry
!= Entry1
)
1004 DbgPrint("Someone changed ppte entry while we slept\n");
1009 * Mark the offset within the section as having valid, in-memory
1012 Entry
= Page
.u
.LowPart
;
1013 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1014 MmSharePageEntrySectionSegment(Segment
, Offset
);
1015 MmUnlockSectionSegment(Segment
);
1018 * Save the swap entry.
1020 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1021 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1026 if (Status
== STATUS_NO_MEMORY
)
1028 MmUnlockAddressSpace(AddressSpace
);
1029 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1034 MmLockAddressSpace(AddressSpace
);
1036 if (!NT_SUCCESS(Status
))
1038 DbgPrint("Unable to create virtual mapping\n");
1041 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1046 PageOp
->Status
= STATUS_SUCCESS
;
1047 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1048 MmReleasePageOp(PageOp
);
1049 DPRINT("Address 0x%.8X\n", Address
);
1050 return(STATUS_SUCCESS
);
1055 * If the section offset is already in-memory and valid then just
1056 * take another reference to the page
1059 Page
= (LARGE_INTEGER
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
1060 MmReferencePage(Page
);
1061 MmSharePageEntrySectionSegment(Segment
, Offset
);
1062 MmUnlockSectionSegment(Segment
);
1064 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1069 if (Status
== STATUS_NO_MEMORY
)
1071 MmUnlockAddressSpace(AddressSpace
);
1072 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1077 MmLockAddressSpace(AddressSpace
);
1079 if (!NT_SUCCESS(Status
))
1081 DbgPrint("Unable to create virtual mapping\n");
1084 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1089 PageOp
->Status
= STATUS_SUCCESS
;
1090 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1091 MmReleasePageOp(PageOp
);
1092 DPRINT("Address 0x%.8X\n", Address
);
1093 return(STATUS_SUCCESS
);
1098 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1099 MEMORY_AREA
* MemoryArea
,
1103 PMM_SECTION_SEGMENT Segment
;
1104 PSECTION_OBJECT Section
;
1105 PHYSICAL_ADDRESS OldPage
;
1106 PHYSICAL_ADDRESS NewPage
;
1113 LARGE_INTEGER Timeout
;
1116 * Check if the page has been paged out or has already been set readwrite
1118 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1119 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1121 DPRINT("Address 0x%.8X\n", Address
);
1122 return(STATUS_SUCCESS
);
1126 * Find the offset of the page
1128 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1129 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1131 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1132 Section
= MemoryArea
->Data
.SectionData
.Section
;
1133 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1134 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1139 MmLockSectionSegment(Segment
);
1144 if (MmGetPageEntrySectionSegment(Segment
, Offset
) == 0)
1146 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1149 MmUnlockSectionSegment(Segment
);
1151 * Check if we are doing COW
1153 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1154 (Region
->Protect
== PAGE_READWRITE
||
1155 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1157 DPRINT("Address 0x%.8X\n", Address
);
1158 return(STATUS_UNSUCCESSFUL
);
1162 * Get or create a pageop
1164 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1165 MM_PAGEOP_ACCESSFAULT
);
1168 DPRINT1("MmGetPageOp failed\n");
1173 * Wait for any other operations to complete
1175 if (PageOp
->Thread
!= PsGetCurrentThread())
1177 MmUnlockAddressSpace(AddressSpace
);
1178 Timeout
.QuadPart
= -100000000LL; // 10 sec
1179 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
1185 * Check for various strange conditions
1187 if (Status
== STATUS_TIMEOUT
)
1189 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1192 if (PageOp
->Status
== STATUS_PENDING
)
1194 DPRINT1("Woke for page op before completion\n");
1198 * Restart the operation
1200 MmLockAddressSpace(AddressSpace
);
1201 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1202 MmReleasePageOp(PageOp
);
1203 DPRINT("Address 0x%.8X\n", Address
);
1204 return(STATUS_MM_RESTART_OPERATION
);
1208 * Release locks now we have the pageop
1210 MmUnlockAddressSpace(AddressSpace
);
1215 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1216 if (!NT_SUCCESS(Status
))
1224 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1226 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1227 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1228 ExUnmapPage(NewAddress
);
1231 * Delete the old entry.
1233 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1236 * Set the PTE to point to the new page
1238 MmLockAddressSpace(AddressSpace
);
1239 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1244 if (Status
== STATUS_NO_MEMORY
)
1246 MmUnlockAddressSpace(AddressSpace
);
1247 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1252 MmLockAddressSpace(AddressSpace
);
1254 if (!NT_SUCCESS(Status
))
1256 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1260 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1261 if (!NT_SUCCESS(Status
))
1263 DbgPrint("Unable to create virtual mapping\n");
1268 MmLockPage(NewPage
);
1272 * Unshare the old page.
1274 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1275 MmLockSectionSegment(Segment
);
1276 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
);
1277 MmUnlockSectionSegment(Segment
);
1278 MmReleasePageMemoryConsumer(MC_USER
, OldPage
);
1280 PageOp
->Status
= STATUS_SUCCESS
;
1281 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1282 MmReleasePageOp(PageOp
);
1283 DPRINT("Address 0x%.8X\n", Address
);
1284 return(STATUS_SUCCESS
);
1288 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1290 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1292 PHYSICAL_ADDRESS Page
;
1294 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1295 MmDeleteVirtualMapping(Process
,
1302 PageOutContext
->WasDirty
= TRUE
;
1304 if (!PageOutContext
->Private
)
1306 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1307 PageOutContext
->Segment
,
1308 PageOutContext
->Offset
,
1309 PageOutContext
->WasDirty
);
1311 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1312 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1316 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1317 MEMORY_AREA
* MemoryArea
,
1321 PHYSICAL_ADDRESS PhysicalAddress
;
1322 MM_SECTION_PAGEOUT_CONTEXT Context
;
1323 SWAPENTRY SwapEntry
;
1328 PFILE_OBJECT FileObject
;
1330 BOOLEAN DirectMapped
;
1331 BOOLEAN IsImageSection
;
1333 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1336 * Get the segment and section.
1338 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1339 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1341 Context
.Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
1342 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1344 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1346 FileObject
= Context
.Section
->FileObject
;
1347 DirectMapped
= FALSE
;
1348 if (FileObject
!= NULL
)
1350 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1353 * If the file system is letting us go directly to the cache and the
1354 * memory area was mapped at an offset in the file which is page aligned
1355 * then note this is a direct mapped page.
1357 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1358 (FileOffset
% PAGE_SIZE
) == 0 &&
1359 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1361 DirectMapped
= TRUE
;
1367 * This should never happen since mappings of physical memory are never
1368 * placed in the rmap lists.
1370 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1372 DPRINT1("Trying to page out from physical memory section address 0x%X "
1373 "process %d\n", Address
,
1374 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1379 * Get the section segment entry and the physical address.
1381 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1382 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1384 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1385 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1389 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1390 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1393 * Prepare the context structure for the rmap delete call.
1395 Context
.WasDirty
= FALSE
;
1396 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1397 IS_SWAP_FROM_SSE(Entry
) ||
1398 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1400 Context
.Private
= TRUE
;
1404 Context
.Private
= FALSE
;
1408 * Paging out data mapped read-only is easy.
1410 if (Context
.Segment
->Protection
& (PAGE_READONLY
|PAGE_EXECUTE_READ
))
1413 * Read-only data should never be in the swapfile.
1417 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1418 "paddress 0x%.8X\n", SwapEntry
, Address
,
1424 * Read-only data should never be COWed
1426 if (Context
.Private
)
1428 DPRINT1("Had private copy of read-only page.\n");
1433 * Delete all mappings of this page.
1435 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
,
1436 MmPageOutDeleteMapping
);
1437 if (Context
.WasDirty
)
1439 DPRINT1("Had a dirty page of a read-only page.\n");
1443 PageOp
->Status
= STATUS_SUCCESS
;
1444 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1445 MmReleasePageOp(PageOp
);
1446 return(STATUS_SUCCESS
);
1450 * Otherwise we have read-write data.
1454 * Take an additional reference to the page or the cache segment.
1456 if (DirectMapped
&& !Context
.Private
)
1458 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1460 DPRINT1("Direct mapped non private page is not associated with the cache.\n")
1466 MmReferencePage(PhysicalAddress
);
1469 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1472 * If this wasn't a private page then we should have reduced the entry to
1473 * zero by deleting all the rmaps.
1475 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1481 * If the page wasn't dirty then we can just free it as for a readonly page.
1482 * Since we unmapped all the mappings above we know it will not suddenly
1485 if (!Context
.WasDirty
)
1487 if (Context
.Private
)
1489 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1490 if (!(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
) &&
1493 DPRINT1("Private page, non-dirty but not swapped out "
1494 "process %d address 0x%.8X\n",
1495 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0,
1501 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1504 if (!NT_SUCCESS(Status
))
1510 if (DirectMapped
&& !Context
.Private
)
1512 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1513 if (!NT_SUCCESS(Status
))
1515 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1521 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1524 PageOp
->Status
= STATUS_SUCCESS
;
1525 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1526 MmReleasePageOp(PageOp
);
1527 return(STATUS_SUCCESS
);
1531 * If this page was direct mapped from the cache then the cache manager
1532 * will already have taken care of writing it back.
1534 if (DirectMapped
&& !Context
.Private
)
1536 assert(SwapEntry
== 0);
1537 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1538 if (!NT_SUCCESS(Status
))
1540 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
1543 PageOp
->Status
= STATUS_SUCCESS
;
1544 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1545 MmReleasePageOp(PageOp
);
1546 return(STATUS_SUCCESS
);
1550 * If necessary, allocate an entry in the paging file for this page
1552 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1555 SwapEntry
= MmAllocSwapPage();
1558 MmShowOutOfSpaceMessagePagingFile();
1561 * For private pages restore the old mappings.
1563 if (Context
.Private
)
1565 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1567 MemoryArea
->Attributes
,
1570 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1571 MmInsertRmap(PhysicalAddress
,
1572 MemoryArea
->Process
,
1578 * For non-private pages if the page wasn't direct mapped then
1579 * set it back into the section segment entry so we don't loose
1580 * our copy. Otherwise it will be handled by the cache manager.
1582 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1584 MemoryArea
->Attributes
,
1587 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1588 MmInsertRmap(PhysicalAddress
,
1589 MemoryArea
->Process
,
1591 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
,
1592 PhysicalAddress
.u
.LowPart
);
1593 MmSharePageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1595 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1596 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1597 MmReleasePageOp(PageOp
);
1598 return(STATUS_UNSUCCESSFUL
);
1603 * Write the page to the pagefile
1605 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1606 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1607 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1608 if (!NT_SUCCESS(Status
))
1610 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1613 * As above: undo our actions.
1614 * FIXME: Also free the swap page.
1616 if (Context
.Private
)
1618 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1620 MemoryArea
->Attributes
,
1623 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1624 MmInsertRmap(PhysicalAddress
,
1625 MemoryArea
->Process
,
1630 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1632 MemoryArea
->Attributes
,
1635 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1636 MmInsertRmap(PhysicalAddress
,
1637 MemoryArea
->Process
,
1639 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
,
1640 PhysicalAddress
.u
.LowPart
);
1641 MmSharePageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1643 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1644 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1645 MmReleasePageOp(PageOp
);
1646 return(STATUS_UNSUCCESSFUL
);
1650 * Otherwise we have succeeded.
1652 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1653 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1654 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1656 if (Context
.Private
)
1658 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1661 if (!NT_SUCCESS(Status
))
1668 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1669 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1672 PageOp
->Status
= STATUS_SUCCESS
;
1673 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1674 MmReleasePageOp(PageOp
);
1675 return(STATUS_SUCCESS
);
1679 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1680 PMEMORY_AREA MemoryArea
,
1685 PSECTION_OBJECT Section
;
1686 PMM_SECTION_SEGMENT Segment
;
1687 PHYSICAL_ADDRESS PhysicalAddress
;
1688 SWAPENTRY SwapEntry
;
1693 PFILE_OBJECT FileObject
;
1695 BOOLEAN DirectMapped
;
1696 BOOLEAN IsImageSection
;
1698 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1700 Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
1703 * Get the segment and section.
1705 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1706 Section
= MemoryArea
->Data
.SectionData
.Section
;
1707 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1709 FileObject
= Section
->FileObject
;
1710 DirectMapped
= FALSE
;
1711 if (FileObject
!= NULL
)
1713 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1716 * If the file system is letting us go directly to the cache and the
1717 * memory area was mapped at an offset in the file which is page aligned
1718 * then note this is a direct mapped page.
1720 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1721 (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1722 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1724 DirectMapped
= TRUE
;
1729 * This should never happen since mappings of physical memory are never
1730 * placed in the rmap lists.
1732 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1734 DPRINT1("Trying to write back page from physical memory mapped at %X "
1735 "process %d\n", Address
,
1736 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1741 * Get the section segment entry and the physical address.
1743 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1744 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1746 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1747 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1751 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1752 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1755 * Check for a private (COWed) page.
1757 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1758 IS_SWAP_FROM_SSE(Entry
) ||
1759 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1769 * Speculatively set all mappings of the page to clean.
1771 MmSetCleanAllRmaps(PhysicalAddress
);
1774 * If this page was direct mapped from the cache then the cache manager
1775 * will take care of writing it back to disk.
1777 if (DirectMapped
&& !Private
)
1779 assert(SwapEntry
== 0);
1780 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1781 PageOp
->Status
= STATUS_SUCCESS
;
1782 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1783 MmReleasePageOp(PageOp
);
1784 return(STATUS_SUCCESS
);
1788 * If necessary, allocate an entry in the paging file for this page
1790 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1793 SwapEntry
= MmAllocSwapPage();
1796 MmSetDirtyAllRmaps(PhysicalAddress
);
1797 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1798 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1799 MmReleasePageOp(PageOp
);
1800 return(STATUS_UNSUCCESSFUL
);
1805 * Write the page to the pagefile
1807 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1808 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1809 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1810 if (!NT_SUCCESS(Status
))
1812 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1814 MmSetDirtyAllRmaps(PhysicalAddress
);
1815 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1816 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1817 MmReleasePageOp(PageOp
);
1818 return(STATUS_UNSUCCESSFUL
);
1822 * Otherwise we have succeeded.
1824 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1825 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
1826 PageOp
->Status
= STATUS_SUCCESS
;
1827 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1828 MmReleasePageOp(PageOp
);
1829 return(STATUS_SUCCESS
);
1833 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1841 PMEMORY_AREA MemoryArea
;
1842 PMM_SECTION_SEGMENT Segment
;
1846 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1847 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1849 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1850 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1855 if (OldProtect
!= NewProtect
)
1857 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1859 PVOID Address
= BaseAddress
+ (i
* PAGE_SIZE
);
1860 ULONG Protect
= NewProtect
;
1863 * If we doing COW for this segment then check if the page is
1866 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1870 LARGE_INTEGER PhysicalAddress
;
1872 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1873 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1875 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1877 Protect
= PAGE_READONLY
;
1878 if ((Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1879 IS_SWAP_FROM_SSE(Entry
) ||
1880 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
))
1882 Protect
= NewProtect
;
1886 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1888 MmSetPageProtect(AddressSpace
->Process
, BaseAddress
,
1896 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1897 PMEMORY_AREA MemoryArea
,
1907 min(Length
, (ULONG
) (MemoryArea
->BaseAddress
+ MemoryArea
->Length
- BaseAddress
));
1908 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1909 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1911 *OldProtect
= Region
->Protect
;
1912 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
1913 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1914 BaseAddress
, Length
, Region
->Type
, Protect
,
1915 MmAlterViewAttributes
);
1921 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1923 PMEMORY_BASIC_INFORMATION Info
,
1924 PULONG ResultLength
)
1927 PVOID RegionBaseAddress
;
1929 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1930 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1931 Address
, &RegionBaseAddress
);
1934 return STATUS_UNSUCCESSFUL
;
1936 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1937 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
1938 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1939 Info
->RegionSize
= MemoryArea
->Length
;
1940 Info
->State
= MEM_COMMIT
;
1941 Info
->Protect
= Region
->Protect
;
1942 if (MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
)
1944 Info
->Type
= MEM_IMAGE
;
1948 Info
->Type
= MEM_MAPPED
;
1951 return(STATUS_SUCCESS
);
1955 MmpDeleteSection(PVOID ObjectBody
)
1957 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
1959 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
1960 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1964 PMM_SECTION_SEGMENT SectionSegments
;
1966 SectionSegments
= Section
->ImageSection
->Segments
;
1967 NrSegments
= Section
->ImageSection
->NrSegments
;
1969 for (i
= 0; i
< NrSegments
; i
++)
1971 InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
1976 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
1978 if (Section
->FileObject
!= NULL
)
1980 CcRosDereferenceCache(Section
->FileObject
);
1981 ObDereferenceObject(Section
->FileObject
);
1982 Section
->FileObject
= NULL
;
1985 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1987 MmFreePageTablesSectionSegment(Section
->Segment
);
1988 ExFreePool(Section
->Segment
);
1993 MmpCloseSection(PVOID ObjectBody
,
1996 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
1997 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2001 MmpCreateSection(PVOID ObjectBody
,
2003 PWSTR RemainingPath
,
2004 POBJECT_ATTRIBUTES ObjectAttributes
)
2006 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2007 ObjectBody
, Parent
, RemainingPath
);
2009 if (RemainingPath
== NULL
)
2011 return(STATUS_SUCCESS
);
2014 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2016 return(STATUS_UNSUCCESSFUL
);
2018 return(STATUS_SUCCESS
);
2022 MmCreatePhysicalMemorySection(VOID
)
2024 HANDLE PhysSectionH
;
2025 PSECTION_OBJECT PhysSection
;
2027 OBJECT_ATTRIBUTES Obj
;
2028 UNICODE_STRING Name
= UNICODE_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2029 LARGE_INTEGER SectionSize
;
2032 * Create the section mapping physical memory
2034 SectionSize
.QuadPart
= 0xFFFFFFFF;
2035 InitializeObjectAttributes(&Obj
,
2040 Status
= NtCreateSection(&PhysSectionH
,
2044 PAGE_EXECUTE_READWRITE
,
2047 if (!NT_SUCCESS(Status
))
2049 DbgPrint("Failed to create PhysicalMemory section\n");
2052 Status
= ObReferenceObjectByHandle(PhysSectionH
,
2056 (PVOID
*)&PhysSection
,
2058 if (!NT_SUCCESS(Status
))
2060 DbgPrint("Failed to reference PhysicalMemory section\n");
2063 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2064 ObDereferenceObject((PVOID
)PhysSection
);
2066 return(STATUS_SUCCESS
);
2070 MmInitSectionImplementation(VOID
)
2072 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2074 RtlInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2076 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2077 MmSectionObjectType
->TotalObjects
= 0;
2078 MmSectionObjectType
->TotalHandles
= 0;
2079 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2080 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2081 MmSectionObjectType
->PagedPoolCharge
= 0;
2082 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2083 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2084 MmSectionObjectType
->Dump
= NULL
;
2085 MmSectionObjectType
->Open
= NULL
;
2086 MmSectionObjectType
->Close
= MmpCloseSection
;
2087 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2088 MmSectionObjectType
->Parse
= NULL
;
2089 MmSectionObjectType
->Security
= NULL
;
2090 MmSectionObjectType
->QueryName
= NULL
;
2091 MmSectionObjectType
->OkayToClose
= NULL
;
2092 MmSectionObjectType
->Create
= MmpCreateSection
;
2093 MmSectionObjectType
->DuplicationNotify
= NULL
;
2095 return(STATUS_SUCCESS
);
2099 MmCreatePageFileSection(PHANDLE SectionHandle
,
2100 ACCESS_MASK DesiredAccess
,
2101 POBJECT_ATTRIBUTES ObjectAttributes
,
2102 PLARGE_INTEGER UMaximumSize
,
2103 ULONG SectionPageProtection
,
2104 ULONG AllocationAttributes
)
2106 * Create a section which is backed by the pagefile
2109 LARGE_INTEGER MaximumSize
;
2110 PSECTION_OBJECT Section
;
2111 PMM_SECTION_SEGMENT Segment
;
2114 if (UMaximumSize
== NULL
)
2116 return(STATUS_UNSUCCESSFUL
);
2118 MaximumSize
= *UMaximumSize
;
2121 * Check the protection
2123 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2124 SectionPageProtection
)
2126 return(STATUS_INVALID_PAGE_PROTECTION
);
2130 * Create the section
2132 Status
= ObRosCreateObject(SectionHandle
,
2135 MmSectionObjectType
,
2137 if (!NT_SUCCESS(Status
))
2145 Section
->SectionPageProtection
= SectionPageProtection
;
2146 Section
->AllocationAttributes
= AllocationAttributes
;
2147 InitializeListHead(&Section
->ViewListHead
);
2148 KeInitializeSpinLock(&Section
->ViewListLock
);
2149 Section
->FileObject
= NULL
;
2150 Section
->MaximumSize
= MaximumSize
;
2151 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2152 TAG_MM_SECTION_SEGMENT
);
2153 if (Segment
== NULL
)
2155 ZwClose(*SectionHandle
);
2156 ObDereferenceObject(Section
);
2157 return(STATUS_NO_MEMORY
);
2159 Section
->Segment
= Segment
;
2160 Segment
->ReferenceCount
= 1;
2161 ExInitializeFastMutex(&Segment
->Lock
);
2162 Segment
->FileOffset
= 0;
2163 Segment
->Protection
= SectionPageProtection
;
2164 Segment
->Attributes
= AllocationAttributes
;
2165 Segment
->Length
= MaximumSize
.u
.LowPart
;
2166 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2167 Segment
->WriteCopy
= FALSE
;
2168 ObDereferenceObject(Section
);
2169 return(STATUS_SUCCESS
);
2174 MmCreateDataFileSection(PHANDLE SectionHandle
,
2175 ACCESS_MASK DesiredAccess
,
2176 POBJECT_ATTRIBUTES ObjectAttributes
,
2177 PLARGE_INTEGER UMaximumSize
,
2178 ULONG SectionPageProtection
,
2179 ULONG AllocationAttributes
,
2182 * Create a section backed by a data file
2185 PSECTION_OBJECT Section
;
2187 LARGE_INTEGER MaximumSize
;
2188 PFILE_OBJECT FileObject
;
2189 PMM_SECTION_SEGMENT Segment
;
2191 IO_STATUS_BLOCK Iosb
;
2192 LARGE_INTEGER Offset
;
2196 * Check the protection
2198 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2199 SectionPageProtection
)
2201 return(STATUS_INVALID_PAGE_PROTECTION
);
2205 * Read a bit so caching is initiated for the file object.
2206 * This is only needed because MiReadPage currently cannot
2207 * handle non-cached streams.
2209 Offset
.QuadPart
= 0;
2210 Status
= ZwReadFile(FileHandle
,
2219 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2225 * Create the section
2227 Status
= ObRosCreateObject(SectionHandle
,
2230 MmSectionObjectType
,
2232 if (!NT_SUCCESS(Status
))
2240 Section
->SectionPageProtection
= SectionPageProtection
;
2241 Section
->AllocationAttributes
= AllocationAttributes
;
2242 InitializeListHead(&Section
->ViewListHead
);
2243 KeInitializeSpinLock(&Section
->ViewListLock
);
2246 * Check file access required
2248 if (SectionPageProtection
& PAGE_READWRITE
||
2249 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2251 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2255 FileAccess
= FILE_READ_DATA
;
2259 * Reference the file handle
2261 Status
= ObReferenceObjectByHandle(FileHandle
,
2265 (PVOID
*)&FileObject
,
2267 if (!NT_SUCCESS(Status
))
2269 ZwClose(*SectionHandle
);
2270 ObDereferenceObject(Section
);
2275 * We can't do memory mappings if the file system doesn't support the
2278 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2280 ZwClose(*SectionHandle
);
2281 ObDereferenceObject(Section
);
2282 ObDereferenceObject(FileObject
);
2283 return(STATUS_INVALID_FILE_FOR_SECTION
);
2287 * FIXME: Revise this once a locking order for file size changes is
2290 if (UMaximumSize
!= NULL
)
2292 MaximumSize
= *UMaximumSize
;
2297 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2300 if (MaximumSize
.QuadPart
>
2301 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2303 IO_STATUS_BLOCK Iosb
;
2304 Status
= NtSetInformationFile(FileHandle
,
2307 sizeof(LARGE_INTEGER
),
2308 FileAllocationInformation
);
2309 if (!NT_SUCCESS(Status
))
2311 ZwClose(*SectionHandle
);
2312 ObDereferenceObject(Section
);
2313 ObDereferenceObject(FileObject
);
2314 return(STATUS_SECTION_NOT_EXTENDED
);
2321 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2326 if (Status
!= STATUS_SUCCESS
)
2328 ZwClose(*SectionHandle
);
2329 ObDereferenceObject(Section
);
2330 ObDereferenceObject(FileObject
);
2335 * If this file hasn't been mapped as a data file before then allocate a
2336 * section segment to describe the data file mapping
2338 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2340 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2341 TAG_MM_SECTION_SEGMENT
);
2342 if (Segment
== NULL
)
2344 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2345 ZwClose(*SectionHandle
);
2346 ObDereferenceObject(Section
);
2347 ObDereferenceObject(FileObject
);
2348 return(STATUS_NO_MEMORY
);
2350 Section
->Segment
= Segment
;
2351 Segment
->ReferenceCount
= 1;
2352 ExInitializeFastMutex(&Segment
->Lock
);
2354 * Set the lock before assigning the segment to the file object
2356 ExAcquireFastMutex(&Segment
->Lock
);
2357 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2359 Segment
->FileOffset
= 0;
2360 Segment
->Protection
= 0;
2361 Segment
->Attributes
= 0;
2362 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2363 Segment
->Characteristics
= 0;
2364 Segment
->WriteCopy
= FALSE
;
2365 if (AllocationAttributes
& SEC_RESERVE
)
2367 Segment
->Length
= Segment
->RawLength
= 0;
2371 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2372 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2374 Segment
->VirtualAddress
= NULL
;
2379 * If the file is already mapped as a data file then we may need
2383 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2385 Section
->Segment
= Segment
;
2386 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2387 MmLockSectionSegment(Segment
);
2389 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2390 !(AllocationAttributes
& SEC_RESERVE
))
2392 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2393 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2396 MmUnlockSectionSegment(Segment
);
2397 Section
->FileObject
= FileObject
;
2398 Section
->MaximumSize
= MaximumSize
;
2399 CcRosReferenceCache(FileObject
);
2400 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2401 ObDereferenceObject(Section
);
2402 return(STATUS_SUCCESS
);
2405 static ULONG SectionCharacteristicsToProtect
[16] =
2407 PAGE_NOACCESS
, // 0 = NONE
2408 PAGE_NOACCESS
, // 1 = SHARED
2409 PAGE_EXECUTE
, // 2 = EXECUTABLE
2410 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2411 PAGE_READONLY
, // 4 = READABLE
2412 PAGE_READONLY
, // 5 = READABLE, SHARED
2413 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2414 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2415 PAGE_READWRITE
, // 8 = WRITABLE
2416 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2417 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2418 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2419 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2420 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2421 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2422 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2426 MmCreateImageSection(PHANDLE SectionHandle
,
2427 ACCESS_MASK DesiredAccess
,
2428 POBJECT_ATTRIBUTES ObjectAttributes
,
2429 PLARGE_INTEGER UMaximumSize
,
2430 ULONG SectionPageProtection
,
2431 ULONG AllocationAttributes
,
2434 PSECTION_OBJECT Section
;
2436 PFILE_OBJECT FileObject
;
2437 IMAGE_DOS_HEADER DosHeader
;
2438 IO_STATUS_BLOCK Iosb
;
2439 LARGE_INTEGER Offset
;
2440 IMAGE_NT_HEADERS PEHeader
;
2441 PIMAGE_SECTION_HEADER ImageSections
;
2442 PMM_SECTION_SEGMENT SectionSegments
;
2444 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2447 ULONG Characteristics
;
2448 ULONG FileAccess
= 0;
2450 * Check the protection
2452 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2453 SectionPageProtection
)
2455 return(STATUS_INVALID_PAGE_PROTECTION
);
2459 * Specifying a maximum size is meaningless for an image section
2461 if (UMaximumSize
!= NULL
)
2463 return(STATUS_INVALID_PARAMETER_4
);
2467 * Reference the file handle
2469 Status
= ObReferenceObjectByHandle(FileHandle
,
2473 (PVOID
*)&FileObject
,
2475 if (!NT_SUCCESS(Status
))
2481 * Initialized caching for this file object if previously caching
2482 * was initialized for the same on disk file
2484 Status
= CcTryToInitializeFileCache(FileObject
);
2486 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2489 * Read the dos header and check the DOS signature
2491 Offset
.QuadPart
= 0;
2492 Status
= ZwReadFile(FileHandle
,
2501 if (!NT_SUCCESS(Status
))
2503 ObDereferenceObject(FileObject
);
2508 * Check the DOS signature
2510 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2511 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2513 ObDereferenceObject(FileObject
);
2514 return(STATUS_INVALID_IMAGE_FORMAT
);
2518 * Read the PE header
2520 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2521 Status
= ZwReadFile(FileHandle
,
2530 if (!NT_SUCCESS(Status
))
2532 ObDereferenceObject(FileObject
);
2537 * Check the signature
2539 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2540 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2542 ObDereferenceObject(FileObject
);
2543 return(STATUS_INVALID_IMAGE_FORMAT
);
2547 * Read in the section headers
2549 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2550 ImageSections
= ExAllocatePool(NonPagedPool
,
2551 PEHeader
.FileHeader
.NumberOfSections
*
2552 sizeof(IMAGE_SECTION_HEADER
));
2553 if (ImageSections
== NULL
)
2555 ObDereferenceObject(FileObject
);
2556 return(STATUS_NO_MEMORY
);
2559 Status
= ZwReadFile(FileHandle
,
2565 PEHeader
.FileHeader
.NumberOfSections
*
2566 sizeof(IMAGE_SECTION_HEADER
),
2569 if (!NT_SUCCESS(Status
))
2571 ObDereferenceObject(FileObject
);
2572 ExFreePool(ImageSections
);
2575 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2577 ObDereferenceObject(FileObject
);
2578 ExFreePool(ImageSections
);
2579 return(STATUS_INVALID_IMAGE_FORMAT
);
2583 * Create the section
2585 Status
= ObRosCreateObject(SectionHandle
,
2588 MmSectionObjectType
,
2590 if (!NT_SUCCESS(Status
))
2592 ObDereferenceObject(FileObject
);
2593 ExFreePool(ImageSections
);
2600 Section
->SectionPageProtection
= SectionPageProtection
;
2601 Section
->AllocationAttributes
= AllocationAttributes
;
2602 InitializeListHead(&Section
->ViewListHead
);
2603 KeInitializeSpinLock(&Section
->ViewListLock
);
2606 * Check file access required
2608 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2610 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2614 FileAccess
= FILE_READ_DATA
;
2618 * We can't do memory mappings if the file system doesn't support the
2621 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2623 ZwClose(*SectionHandle
);
2624 ObDereferenceObject(Section
);
2625 ObDereferenceObject(FileObject
);
2626 ExFreePool(ImageSections
);
2627 return(STATUS_INVALID_FILE_FOR_SECTION
);
2633 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2638 if (Status
!= STATUS_SUCCESS
)
2640 ZwClose(*SectionHandle
);
2641 ObDereferenceObject(Section
);
2642 ObDereferenceObject(FileObject
);
2643 ExFreePool(ImageSections
);
2648 * allocate the section segments to describe the mapping
2650 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2651 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2652 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2653 if (ImageSectionObject
== NULL
)
2655 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2656 ZwClose(*SectionHandle
);
2657 ObDereferenceObject(Section
);
2658 ObDereferenceObject(FileObject
);
2659 ExFreePool(ImageSections
);
2660 return(STATUS_NO_MEMORY
);
2662 Section
->ImageSection
= ImageSectionObject
;
2663 ImageSectionObject
->NrSegments
= NrSegments
;
2664 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2665 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2666 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2667 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2668 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2669 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2670 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2671 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2672 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2673 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2675 SectionSegments
= ImageSectionObject
->Segments
;
2676 SectionSegments
[0].FileOffset
= 0;
2677 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2678 SectionSegments
[0].Protection
= PAGE_READONLY
;
2679 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2680 SectionSegments
[0].Length
= PAGE_SIZE
;
2681 SectionSegments
[0].Flags
= 0;
2682 SectionSegments
[0].ReferenceCount
= 1;
2683 SectionSegments
[0].VirtualAddress
= 0;
2684 SectionSegments
[0].WriteCopy
= FALSE
;
2685 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2686 for (i
= 1; i
< NrSegments
; i
++)
2688 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2689 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2692 * Set up the protection and write copy variables.
2694 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2695 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2697 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2698 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2700 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2702 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2703 SectionSegments
[i
].WriteCopy
= TRUE
;
2705 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2707 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2708 SectionSegments
[i
].WriteCopy
= TRUE
;
2710 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2712 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2713 SectionSegments
[i
].WriteCopy
= TRUE
;
2717 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2718 SectionSegments
[i
].WriteCopy
= TRUE
;
2722 * Set up the attributes.
2724 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2726 SectionSegments
[i
].Attributes
= 0;
2728 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2730 SectionSegments
[i
].Attributes
= 0;
2732 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2734 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2738 SectionSegments
[i
].Attributes
= 0;
2741 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2742 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2743 SectionSegments
[i
].Flags
= 0;
2744 SectionSegments
[i
].ReferenceCount
= 1;
2745 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2746 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2748 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2749 (LONG
)ImageSectionObject
, 0))
2752 * An other thread has initialized the some image in the background
2754 ExFreePool(ImageSectionObject
);
2755 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2756 Section
->ImageSection
= ImageSectionObject
;
2757 SectionSegments
= ImageSectionObject
->Segments
;
2759 for (i
= 0; i
< NrSegments
; i
++)
2761 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2764 ExFreePool(ImageSections
);
2769 * Create the section
2771 Status
= ObRosCreateObject(SectionHandle
,
2774 MmSectionObjectType
,
2776 if (!NT_SUCCESS(Status
))
2778 ObDereferenceObject(FileObject
);
2785 Section
->SectionPageProtection
= SectionPageProtection
;
2786 Section
->AllocationAttributes
= AllocationAttributes
;
2787 InitializeListHead(&Section
->ViewListHead
);
2788 KeInitializeSpinLock(&Section
->ViewListLock
);
2791 * Check file access required
2793 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2795 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2799 FileAccess
= FILE_READ_DATA
;
2805 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2810 if (Status
!= STATUS_SUCCESS
)
2812 ZwClose(*SectionHandle
);
2813 ObDereferenceObject(Section
);
2814 ObDereferenceObject(FileObject
);
2818 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2819 Section
->ImageSection
= ImageSectionObject
;
2820 SectionSegments
= ImageSectionObject
->Segments
;
2821 NrSegments
= ImageSectionObject
->NrSegments
;
2824 * Otherwise just reference all the section segments
2826 for (i
= 0; i
< NrSegments
; i
++)
2828 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2832 Section
->FileObject
= FileObject
;
2833 CcRosReferenceCache(FileObject
);
2834 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2835 ObDereferenceObject(Section
);
2836 return(STATUS_SUCCESS
);
2843 NtCreateSection (OUT PHANDLE SectionHandle
,
2844 IN ACCESS_MASK DesiredAccess
,
2845 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2846 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
2847 IN ULONG SectionPageProtection OPTIONAL
,
2848 IN ULONG AllocationAttributes
,
2849 IN HANDLE FileHandle OPTIONAL
)
2851 if (AllocationAttributes
& SEC_IMAGE
)
2853 return(MmCreateImageSection(SectionHandle
,
2857 SectionPageProtection
,
2858 AllocationAttributes
,
2861 else if (FileHandle
!= NULL
)
2863 return(MmCreateDataFileSection(SectionHandle
,
2867 SectionPageProtection
,
2868 AllocationAttributes
,
2873 return(MmCreatePageFileSection(SectionHandle
,
2877 SectionPageProtection
,
2878 AllocationAttributes
));
2883 /**********************************************************************
2901 NtOpenSection(PHANDLE SectionHandle
,
2902 ACCESS_MASK DesiredAccess
,
2903 POBJECT_ATTRIBUTES ObjectAttributes
)
2909 Status
= ObOpenObjectByName(ObjectAttributes
,
2910 MmSectionObjectType
,
2921 MmMapViewOfSegment(PEPROCESS Process
,
2922 PMADDRESS_SPACE AddressSpace
,
2923 PSECTION_OBJECT Section
,
2924 PMM_SECTION_SEGMENT Segment
,
2935 Status
= MmCreateMemoryArea(Process
,
2937 MEMORY_AREA_SECTION_VIEW
,
2944 if (!NT_SUCCESS(Status
))
2946 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
2947 (*BaseAddress
), (*BaseAddress
) + ViewSize
);
2951 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
2952 InsertTailList(&Section
->ViewListHead
,
2953 &MArea
->Data
.SectionData
.ViewListEntry
);
2954 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
2956 ObReferenceObjectByPointer((PVOID
)Section
,
2959 ExGetPreviousMode());
2960 MArea
->Data
.SectionData
.Segment
= Segment
;
2961 MArea
->Data
.SectionData
.Section
= Section
;
2962 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
2963 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
2964 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
2965 ViewSize
, 0, Protect
);
2967 return(STATUS_SUCCESS
);
2971 /**********************************************************************
2973 * NtMapViewOfSection
2976 * Maps a view of a section into the virtual address space of a
2981 * Handle of the section.
2984 * Handle of the process.
2987 * Desired base address (or NULL) on entry;
2988 * Actual base address of the view on exit.
2991 * Number of high order address bits that must be zero.
2994 * Size in bytes of the initially committed section of
2998 * Offset in bytes from the beginning of the section
2999 * to the beginning of the view.
3002 * Desired length of map (or zero to map all) on entry
3003 * Actual length mapped on exit.
3005 * InheritDisposition
3006 * Specified how the view is to be shared with
3010 * Type of allocation for the pages.
3013 * Protection for the committed region of the view.
3021 NtMapViewOfSection(HANDLE SectionHandle
,
3022 HANDLE ProcessHandle
,
3026 PLARGE_INTEGER SectionOffset
,
3028 SECTION_INHERIT InheritDisposition
,
3029 ULONG AllocationType
,
3032 PSECTION_OBJECT Section
;
3035 PMADDRESS_SPACE AddressSpace
;
3037 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3038 PROCESS_VM_OPERATION
,
3043 if (!NT_SUCCESS(Status
))
3048 AddressSpace
= &Process
->AddressSpace
;
3050 Status
= ObReferenceObjectByHandle(SectionHandle
,
3052 MmSectionObjectType
,
3056 if (!(NT_SUCCESS(Status
)))
3058 DPRINT("ObReference failed rc=%x\n",Status
);
3059 ObDereferenceObject(Process
);
3063 Status
= MmMapViewOfSection(Section
,
3074 ObDereferenceObject(Section
);
3075 ObDereferenceObject(Process
);
3081 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3082 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
3087 PFILE_OBJECT FileObject
;
3090 SWAPENTRY SavedSwapEntry
;
3092 LARGE_INTEGER Timeout
;
3094 PSECTION_OBJECT Section
;
3095 PMM_SECTION_SEGMENT Segment
;
3097 MArea
= (PMEMORY_AREA
)Context
;
3099 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3101 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3103 Section
= MArea
->Data
.SectionData
.Section
;
3104 Segment
= MArea
->Data
.SectionData
.Segment
;
3107 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3111 MmUnlockSectionSegment(Segment
);
3112 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3114 Timeout
.QuadPart
= -100000000LL; // 10 sec
3115 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
3120 if (Status
!= STATUS_SUCCESS
)
3122 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3126 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3127 MmLockSectionSegment(Segment
);
3128 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
3129 MmReleasePageOp(PageOp
);
3130 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3133 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3136 * For a dirty, datafile, non-private page mark it as dirty in the
3139 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3141 if (PhysAddr
.QuadPart
== PAGE_FROM_SSE(Entry
) && Dirty
)
3143 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3144 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3145 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3146 assert(SwapEntry
== 0);
3152 MmFreeSwapPage(SwapEntry
);
3154 else if (PhysAddr
.QuadPart
!= 0)
3156 if (IS_SWAP_FROM_SSE(Entry
) ||
3157 PhysAddr
.QuadPart
!= (PAGE_FROM_SSE(Entry
)))
3160 * Just dereference private pages
3162 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysAddr
);
3163 if (SavedSwapEntry
!= 0)
3165 MmFreeSwapPage(SavedSwapEntry
);
3166 MmSetSavedSwapEntryPage(PhysAddr
, 0);
3168 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3169 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3173 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3174 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
);
3175 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3184 MmUnmapViewOfSection(PEPROCESS Process
,
3188 PMEMORY_AREA MemoryArea
;
3189 PMADDRESS_SPACE AddressSpace
;
3190 PSECTION_OBJECT Section
;
3191 PMM_SECTION_SEGMENT Segment
;
3193 PLIST_ENTRY CurrentEntry
;
3194 PMM_REGION CurrentRegion
;
3198 AddressSpace
= &Process
->AddressSpace
;
3200 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3201 Process
, BaseAddress
);
3202 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3204 if (MemoryArea
== NULL
)
3206 return(STATUS_UNSUCCESSFUL
);
3209 MemoryArea
->DeleteInProgress
= TRUE
;
3210 Section
= MemoryArea
->Data
.SectionData
.Section
;
3211 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3213 MmLockSectionSegment(Segment
);
3214 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3215 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3216 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3218 CurrentEntry
= MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
;
3219 while (CurrentEntry
!= &MemoryArea
->Data
.SectionData
.RegionListHead
)
3222 CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3223 CurrentEntry
= CurrentEntry
->Flink
;
3224 ExFreePool(CurrentRegion
);
3227 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3229 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
3237 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
3243 MmUnlockSectionSegment(Segment
);
3244 ObDereferenceObject(Section
);
3245 return(STATUS_SUCCESS
);
3248 /**********************************************************************
3250 * NtUnmapViewOfSection
3265 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3271 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3272 ProcessHandle
, BaseAddress
);
3274 DPRINT("Referencing process\n");
3275 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3276 PROCESS_VM_OPERATION
,
3281 if (!NT_SUCCESS(Status
))
3283 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3287 MmLockAddressSpace(&Process
->AddressSpace
);
3288 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3289 MmUnlockAddressSpace(&Process
->AddressSpace
);
3291 ObDereferenceObject(Process
);
3298 NtQuerySection (IN HANDLE SectionHandle
,
3299 IN CINT SectionInformationClass
,
3300 OUT PVOID SectionInformation
,
3302 OUT PULONG ResultLength
)
3304 * FUNCTION: Queries the information of a section object.
3306 * SectionHandle = Handle to the section link object
3307 * SectionInformationClass = Index to a certain information structure
3308 * SectionInformation (OUT)= Caller supplies storage for resulting
3310 * Length = Size of the supplied storage
3311 * ResultLength = Data written
3316 PSECTION_OBJECT Section
;
3319 Status
= ObReferenceObjectByHandle(SectionHandle
,
3321 MmSectionObjectType
,
3325 if (!(NT_SUCCESS(Status
)))
3330 switch (SectionInformationClass
)
3332 case SectionBasicInformation
:
3334 PSECTION_BASIC_INFORMATION Sbi
;
3336 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3338 ObDereferenceObject(Section
);
3339 return(STATUS_INFO_LENGTH_MISMATCH
);
3342 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3344 Sbi
->BaseAddress
= 0;
3345 Sbi
->Attributes
= 0;
3346 Sbi
->Size
.QuadPart
= 0;
3348 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3349 Status
= STATUS_SUCCESS
;
3353 case SectionImageInformation
:
3355 PSECTION_IMAGE_INFORMATION Sii
;
3357 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3359 ObDereferenceObject(Section
);
3360 return(STATUS_INFO_LENGTH_MISMATCH
);
3363 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3364 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3365 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3367 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3368 ImageSectionObject
= Section
->ImageSection
;
3370 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3371 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3372 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3373 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3374 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
3375 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
3376 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3377 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3378 Sii
->Executable
= ImageSectionObject
->Executable
;
3380 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3381 Status
= STATUS_SUCCESS
;
3387 Status
= STATUS_INVALID_INFO_CLASS
;
3389 ObDereferenceObject(Section
);
3395 NtExtendSection(IN HANDLE SectionHandle
,
3396 IN ULONG NewMaximumSize
)
3399 return(STATUS_NOT_IMPLEMENTED
);
3403 /**********************************************************************
3405 * MmAllocateSection@4
3415 * Code taken from ntoskrnl/mm/special.c.
3420 MmAllocateSection (IN ULONG Length
)
3426 PMADDRESS_SPACE AddressSpace
;
3428 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3430 AddressSpace
= MmGetKernelAddressSpace();
3432 MmLockAddressSpace(AddressSpace
);
3433 Status
= MmCreateMemoryArea (NULL
,
3442 if (!NT_SUCCESS(Status
))
3444 MmUnlockAddressSpace(AddressSpace
);
3447 MmUnlockAddressSpace(AddressSpace
);
3448 DPRINT("Result %p\n",Result
);
3449 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3451 PHYSICAL_ADDRESS Page
;
3453 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3454 if (!NT_SUCCESS(Status
))
3456 DbgPrint("Unable to allocate page\n");
3459 Status
= MmCreateVirtualMapping (NULL
,
3460 (Result
+ (i
* PAGE_SIZE
)),
3464 if (!NT_SUCCESS(Status
))
3466 DbgPrint("Unable to create virtual mapping\n");
3470 return ((PVOID
)Result
);
3474 /**********************************************************************
3476 * MmMapViewOfSection
3479 * Maps a view of a section into the virtual address space of a
3484 * Pointer to the section object.
3487 * Pointer to the process.
3490 * Desired base address (or NULL) on entry;
3491 * Actual base address of the view on exit.
3494 * Number of high order address bits that must be zero.
3497 * Size in bytes of the initially committed section of
3501 * Offset in bytes from the beginning of the section
3502 * to the beginning of the view.
3505 * Desired length of map (or zero to map all) on entry
3506 * Actual length mapped on exit.
3508 * InheritDisposition
3509 * Specified how the view is to be shared with
3513 * Type of allocation for the pages.
3516 * Protection for the committed region of the view.
3524 MmMapViewOfSection(IN PVOID SectionObject
,
3525 IN PEPROCESS Process
,
3526 IN OUT PVOID
*BaseAddress
,
3528 IN ULONG CommitSize
,
3529 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3530 IN OUT PULONG ViewSize
,
3531 IN SECTION_INHERIT InheritDisposition
,
3532 IN ULONG AllocationType
,
3535 PSECTION_OBJECT Section
;
3536 PMADDRESS_SPACE AddressSpace
;
3538 NTSTATUS Status
= STATUS_SUCCESS
;
3542 Section
= (PSECTION_OBJECT
)SectionObject
;
3543 AddressSpace
= &Process
->AddressSpace
;
3545 MmLockAddressSpace(AddressSpace
);
3547 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3553 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3554 PMM_SECTION_SEGMENT SectionSegments
;
3556 ImageSectionObject
= Section
->ImageSection
;
3557 SectionSegments
= ImageSectionObject
->Segments
;
3558 NrSegments
= ImageSectionObject
->NrSegments
;
3561 ImageBase
= *BaseAddress
;
3562 if (ImageBase
== NULL
)
3564 ImageBase
= ImageSectionObject
->ImageBase
;
3568 for (i
= 0; i
< NrSegments
; i
++)
3570 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3573 MaxExtent
= (ULONG
)(SectionSegments
[i
].VirtualAddress
+
3574 SectionSegments
[i
].Length
);
3575 ImageSize
= max(ImageSize
, MaxExtent
);
3579 /* Check there is enough space to map the section at that point. */
3580 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3581 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3583 /* Fail if the user requested a fixed base address. */
3584 if ((*BaseAddress
) != NULL
)
3586 MmUnlockAddressSpace(AddressSpace
);
3587 return(STATUS_UNSUCCESSFUL
);
3589 /* Otherwise find a gap to map the image. */
3590 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3591 if (ImageBase
== NULL
)
3593 MmUnlockAddressSpace(AddressSpace
);
3594 return(STATUS_UNSUCCESSFUL
);
3598 for (i
= 0; i
< NrSegments
; i
++)
3602 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3604 SBaseAddress
= (PVOID
)
3605 (ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3606 MmLockSectionSegment(&SectionSegments
[i
]);
3607 Status
= MmMapViewOfSegment(Process
,
3610 &SectionSegments
[i
],
3612 SectionSegments
[i
].Length
,
3613 SectionSegments
[i
].Protection
,
3614 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3616 MmUnlockSectionSegment(&SectionSegments
[i
]);
3617 if (!NT_SUCCESS(Status
))
3619 MmUnlockAddressSpace(AddressSpace
);
3625 *BaseAddress
= ImageBase
;
3629 if (SectionOffset
== NULL
)
3635 ViewOffset
= SectionOffset
->u
.LowPart
;
3638 if ((ViewOffset
% PAGE_SIZE
) != 0)
3640 MmUnlockAddressSpace(AddressSpace
);
3641 return(STATUS_MAPPED_ALIGNMENT
);
3644 if ((*ViewSize
) == 0)
3646 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3648 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3650 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3653 MmLockSectionSegment(Section
->Segment
);
3654 Status
= MmMapViewOfSegment(Process
,
3662 (AllocationType
& MEM_TOP_DOWN
));
3663 MmUnlockSectionSegment(Section
->Segment
);
3664 if (!NT_SUCCESS(Status
))
3666 MmUnlockAddressSpace(AddressSpace
);
3671 MmUnlockAddressSpace(AddressSpace
);
3673 return(STATUS_SUCCESS
);
3680 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3681 IN PLARGE_INTEGER NewFileSize
)
3692 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
3702 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3703 IN MMFLUSH_TYPE FlushType
)
3707 case MmFlushForDelete
:
3708 if (SectionObjectPointer
->ImageSectionObject
||
3709 SectionObjectPointer
->DataSectionObject
)
3713 CcRosSetRemoveOnClose(SectionObjectPointer
);
3715 case MmFlushForWrite
:
3725 MmForceSectionClosed (DWORD Unknown0
,
3737 MmMapViewInSystemSpace (IN PVOID SectionObject
,
3738 OUT PVOID
* MappedBase
,
3739 IN OUT PULONG ViewSize
)
3741 PSECTION_OBJECT Section
;
3742 PMADDRESS_SPACE AddressSpace
;
3745 DPRINT("MmMapViewInSystemSpace() called\n");
3747 Section
= (PSECTION_OBJECT
)SectionObject
;
3748 AddressSpace
= MmGetKernelAddressSpace();
3750 MmLockAddressSpace(AddressSpace
);
3753 if ((*ViewSize
) == 0)
3755 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3757 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
3759 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3762 MmLockSectionSegment(Section
->Segment
);
3765 Status
= MmMapViewOfSegment(NULL
,
3775 MmUnlockSectionSegment(Section
->Segment
);
3776 MmUnlockAddressSpace(AddressSpace
);
3786 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
3788 PMEMORY_AREA MemoryArea
;
3789 PMADDRESS_SPACE AddressSpace
;
3790 PSECTION_OBJECT Section
;
3791 PMM_SECTION_SEGMENT Segment
;
3793 PLIST_ENTRY CurrentEntry
;
3794 PMM_REGION CurrentRegion
;
3797 DPRINT("MmUnmapViewInSystemSpace() called\n");
3799 AddressSpace
= MmGetKernelAddressSpace();
3801 DPRINT("Opening memory area at base address %x\n",
3803 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3805 if (MemoryArea
== NULL
)
3807 return STATUS_UNSUCCESSFUL
;
3810 MemoryArea
->DeleteInProgress
= TRUE
;
3811 Section
= MemoryArea
->Data
.SectionData
.Section
;
3812 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3814 MmLockSectionSegment(Segment
);
3815 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3816 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3817 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3819 CurrentEntry
= MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
;
3820 while (CurrentEntry
!= &MemoryArea
->Data
.SectionData
.RegionListHead
)
3823 CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3824 CurrentEntry
= CurrentEntry
->Flink
;
3825 ExFreePool(CurrentRegion
);
3828 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3830 Status
= MmFreeMemoryArea(AddressSpace
,
3838 Status
= MmFreeMemoryArea(AddressSpace
,
3845 MmUnlockSectionSegment(Segment
);
3846 ObDereferenceObject(Section
);
3848 return(STATUS_SUCCESS
);
3856 MmSetBankedSection (DWORD Unknown0
,
3864 return (STATUS_NOT_IMPLEMENTED
);
3868 /**********************************************************************
3873 * Creates a section object.
3876 * SectionObjiect (OUT)
3877 * Caller supplied storage for the resulting pointer
3878 * to a SECTION_OBJECT instance;
3881 * Specifies the desired access to the section can be a
3883 * STANDARD_RIGHTS_REQUIRED |
3885 * SECTION_MAP_WRITE |
3886 * SECTION_MAP_READ |
3887 * SECTION_MAP_EXECUTE
3889 * ObjectAttributes [OPTIONAL]
3890 * Initialized attributes for the object can be used
3891 * to create a named section;
3894 * Maximizes the size of the memory section. Must be
3895 * non-NULL for a page-file backed section.
3896 * If value specified for a mapped file and the file is
3897 * not large enough, file will be extended.
3899 * SectionPageProtection
3900 * Can be a combination of:
3906 * AllocationAttributes
3907 * Can be a combination of:
3912 * Handle to a file to create a section mapped to a file
3913 * instead of a memory backed section;
3924 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
3925 IN ACCESS_MASK DesiredAccess
,
3926 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3927 IN PLARGE_INTEGER MaximumSize
,
3928 IN ULONG SectionPageProtection
,
3929 IN ULONG AllocationAttributes
,
3930 IN HANDLE FileHandle OPTIONAL
,
3931 IN PFILE_OBJECT File OPTIONAL
)
3933 return (STATUS_NOT_IMPLEMENTED
);