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.81 2002/05/13 18:10:40 chorns 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 #include <ddk/ntddk.h>
33 #include <internal/mm.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37 #include <internal/cc.h>
38 #include <ddk/ntifs.h>
41 #include <internal/debug.h>
43 /* TYPES *********************************************************************/
47 PSECTION_OBJECT Section
;
48 PMM_SECTION_SEGMENT Segment
;
52 } MM_SECTION_PAGEOUT_CONTEXT
;
54 /* GLOBALS *******************************************************************/
56 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
58 static GENERIC_MAPPING MmpSectionMapping
= {
59 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
60 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
61 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
64 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
65 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
67 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
68 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
69 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
70 #define MAX_SHARE_COUNT 0x7FF
71 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
72 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
73 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
75 /* FUNCTIONS *****************************************************************/
78 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
82 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
84 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
86 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
92 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
94 if (FileObject
->SectionObjectPointers
->ImageSectionObject
!= NULL
)
96 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
101 (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointers
->
104 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
106 if (ImageSectionObject
->Segments
[i
].ReferenceCount
!= 0)
108 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
109 ImageSectionObject
->Segments
[i
].ReferenceCount
);
112 MmFreePageTablesSectionSegment(&ImageSectionObject
->Segments
[i
]);
114 ExFreePool(ImageSectionObject
);
115 FileObject
->SectionObjectPointers
->ImageSectionObject
= NULL
;
117 if (FileObject
->SectionObjectPointers
->DataSectionObject
!= NULL
)
119 PMM_SECTION_SEGMENT Segment
;
121 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointers
->
124 if (Segment
->ReferenceCount
!= 0)
126 DPRINT1("Data segment still referenced\n");
129 MmFreePageTablesSectionSegment(Segment
);
131 FileObject
->SectionObjectPointers
->DataSectionObject
= NULL
;
136 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
140 return(STATUS_UNSUCCESSFUL
);
144 MmLockSection(PSECTION_OBJECT Section
)
146 KeWaitForSingleObject(&Section
->Lock
,
154 MmUnlockSection(PSECTION_OBJECT Section
)
156 KeReleaseMutex(&Section
->Lock
, FALSE
);
160 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
162 KeWaitForSingleObject(&Segment
->Lock
,
170 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
172 KeReleaseMutex(&Segment
->Lock
, FALSE
);
176 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
180 PSECTION_PAGE_TABLE Table
;
181 ULONG DirectoryOffset
;
184 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
185 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
189 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
190 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
191 TAG_SECTION_PAGE_TABLE
);
192 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
193 DPRINT("Table %x\n", Table
);
195 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
196 Table
->Entry
[TableOffset
] = Entry
;
201 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
204 PSECTION_PAGE_TABLE Table
;
206 ULONG DirectoryOffset
;
209 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
211 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
212 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
213 DPRINT("Table %x\n", Table
);
218 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
219 Entry
= Table
->Entry
[TableOffset
];
224 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
229 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
232 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
235 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
237 DPRINT1("Maximum share count reached\n");
240 if (IS_SWAP_FROM_SSE(Entry
))
244 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
245 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
249 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
250 PMM_SECTION_SEGMENT Segment
,
256 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
259 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
262 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
264 DPRINT1("Zero share count for unshare\n");
267 if (IS_SWAP_FROM_SSE(Entry
))
271 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
273 * If we reducing the share count of this entry to zero then set the entry
274 * to zero and tell the cache the page is no longer mapped.
276 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
278 PFILE_OBJECT FileObject
;
279 PREACTOS_COMMON_FCB_HEADER Fcb
;
281 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
282 FileObject
= Section
->FileObject
;
283 if (FileObject
!= NULL
)
285 Fcb
= (PREACTOS_COMMON_FCB_HEADER
)FileObject
->FsContext
;
287 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
288 (Offset
% PAGESIZE
) == 0)
291 Status
= CcRosUnmapCacheSegment(Fcb
->Bcb
, Offset
, Dirty
);
292 if (!NT_SUCCESS(Status
))
301 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
303 return(SHARE_COUNT_FROM_SSE(Entry
) > 1);
307 MiReadPage(PMEMORY_AREA MemoryArea
,
308 PLARGE_INTEGER Offset
,
311 * FUNCTION: Read a page for a section backed memory area.
313 * MemoryArea - Memory area to read the page for.
314 * Offset - Offset of the page to read.
315 * Page - Variable that receives a page contains the read data.
318 IO_STATUS_BLOCK IoStatus
;
319 PFILE_OBJECT FileObject
;
322 PREACTOS_COMMON_FCB_HEADER Fcb
;
324 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
325 Fcb
= (PREACTOS_COMMON_FCB_HEADER
)FileObject
->FsContext
;
328 * If the file system is letting us go directly to the cache and the
329 * memory area was mapped at an offset in the file which is page aligned
330 * then get the related cache segment.
332 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
333 (Offset
->QuadPart
% PAGESIZE
) == 0)
338 PCACHE_SEGMENT CacheSeg
;
339 LARGE_INTEGER SegOffset
;
340 PHYSICAL_ADDRESS Addr
;
343 * Get the related cache segment; we use a lower level interface than
344 * filesystems do because it is safe for us to use an offset with a
345 * alignment less than the file system block size.
347 Status
= CcRosGetCacheSegment(Fcb
->Bcb
,
348 (ULONG
)Offset
->QuadPart
,
353 if (!NT_SUCCESS(Status
))
360 * If the cache segment isn't up to date then call the file
361 * system to read in the data.
364 Mdl
= MmCreateMdl(NULL
, BaseAddress
, Fcb
->Bcb
->CacheSegmentSize
);
365 MmBuildMdlForNonPagedPool(Mdl
);
366 SegOffset
.QuadPart
= BaseOffset
;
367 Status
= IoPageRead(FileObject
,
372 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
374 CcRosReleaseCacheSegment(Fcb
->Bcb
, CacheSeg
, FALSE
, FALSE
,
380 * Retrieve the page from the cache segment that we actually want.
382 Addr
= MmGetPhysicalAddress(BaseAddress
+
383 Offset
->QuadPart
- BaseOffset
);
384 (*Page
) = (ULONG_PTR
)Addr
.QuadPart
;
385 MmReferencePage((*Page
));
387 CcRosReleaseCacheSegment(Fcb
->Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
388 return(STATUS_SUCCESS
);
393 * Allocate a page, this is rather complicated by the possibility
394 * we might have to move other things out of memory
396 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
397 if (!NT_SUCCESS(Status
))
403 * Create an mdl to hold the page we are going to read data into.
405 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
406 MmBuildMdlFromPages(Mdl
, (PULONG
)Page
);
408 * Call the FSD to read the page
410 Status
= IoPageRead(FileObject
,
420 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
421 MEMORY_AREA
* MemoryArea
,
425 LARGE_INTEGER Offset
;
429 PSECTION_OBJECT Section
;
430 PMM_SECTION_SEGMENT Segment
;
437 * There is a window between taking the page fault and locking the
438 * address space when another thread could load the page so we check
441 if (MmIsPagePresent(NULL
, Address
))
445 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
447 return(STATUS_SUCCESS
);
450 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
451 Offset
.QuadPart
= (PAddress
- (ULONG
)MemoryArea
->BaseAddress
) +
452 MemoryArea
->Data
.SectionData
.ViewOffset
;
457 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
458 Section
= MemoryArea
->Data
.SectionData
.Section
;
459 MmLockSection(Section
);
460 MmLockSectionSegment(Segment
);
463 * Get or create a page operation descriptor
465 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
.u
.LowPart
,
469 DPRINT1("MmGetPageOp failed\n");
474 * Check if someone else is already handling this fault, if so wait
477 if (PageOp
->Thread
!= PsGetCurrentThread())
479 MmUnlockSectionSegment(Segment
);
480 MmUnlockSection(Section
);
481 MmUnlockAddressSpace(AddressSpace
);
482 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
488 * Check for various strange conditions
490 if (Status
!= STATUS_SUCCESS
)
492 DPRINT1("Failed to wait for page op\n");
495 if (PageOp
->Status
== STATUS_PENDING
)
497 DPRINT1("Woke for page op before completion\n");
501 * If this wasn't a pagein then restart the operation
503 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
505 MmLockAddressSpace(AddressSpace
);
506 MmReleasePageOp(PageOp
);
507 DPRINT("Address 0x%.8X\n", Address
);
508 return(STATUS_MM_RESTART_OPERATION
);
511 * If the thread handling this fault has failed then we don't retry
513 if (!NT_SUCCESS(PageOp
->Status
))
515 MmLockAddressSpace(AddressSpace
);
516 DPRINT("Address 0x%.8X\n", Address
);
517 return(PageOp
->Status
);
519 MmLockAddressSpace(AddressSpace
);
520 MmLockSection(Section
);
521 MmLockSectionSegment(Segment
);
523 * If the completed fault was for another address space then set the
526 if (!MmIsPagePresent(NULL
, Address
))
528 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
.u
.LowPart
);
531 MmUnlockSectionSegment(Segment
);
532 MmUnlockSection(Section
);
533 MmReleasePageOp(PageOp
);
534 return(STATUS_MM_RESTART_OPERATION
);
537 Page
= (ULONG_PTR
)(PAGE_FROM_SSE(Entry
));
538 MmReferencePage(Page
);
539 MmSharePageEntrySectionSegment(Segment
, Offset
.u
.LowPart
);
541 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
546 if (!NT_SUCCESS(Status
))
548 DbgPrint("Unable to create virtual mapping\n");
551 MmInsertRmap(Page
, PsGetCurrentProcess(),
552 (PVOID
)PAGE_ROUND_DOWN(Address
));
556 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
558 MmUnlockSectionSegment(Segment
);
559 MmUnlockSection(Section
);
560 MmReleasePageOp(PageOp
);
561 DPRINT("Address 0x%.8X\n", Address
);
562 return(STATUS_SUCCESS
);
566 * Must be private page we have swapped out.
568 if (MmIsPageSwapEntry(NULL
, (PVOID
)PAddress
))
573 MmUnlockSectionSegment(Segment
);
574 MmUnlockSection(Section
);
576 MmDeletePageFileMapping(NULL
, (PVOID
)PAddress
, &SwapEntry
);
578 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
579 if (!NT_SUCCESS(Status
))
584 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
585 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
586 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
587 if (!NT_SUCCESS(Status
))
592 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
594 MemoryArea
->Attributes
,
597 while (Status
== STATUS_NO_MEMORY
)
599 MmUnlockAddressSpace(AddressSpace
);
600 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
602 MemoryArea
->Attributes
,
605 MmLockAddressSpace(AddressSpace
);
607 if (!NT_SUCCESS(Status
))
609 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
615 * Store the swap entry for later use.
617 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
620 * Add the page to the process's working set
622 MmInsertRmap(Page
, PsGetCurrentProcess(),
623 (PVOID
)PAGE_ROUND_DOWN(Address
));
626 * Finish the operation
630 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
632 PageOp
->Status
= STATUS_SUCCESS
;
633 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
634 MmReleasePageOp(PageOp
);
635 DPRINT("Address 0x%.8X\n", Address
);
636 return(STATUS_SUCCESS
);
640 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
642 if (Section
->Flags
& SO_PHYSICAL_MEMORY
)
645 * Just map the desired physical page
647 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
649 MemoryArea
->Attributes
,
653 * Don't add an rmap entry since the page mapped could be for
658 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
662 * Cleanup and release locks
664 PageOp
->Status
= STATUS_SUCCESS
;
665 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
666 MmReleasePageOp(PageOp
);
667 MmUnlockSectionSegment(Segment
);
668 MmUnlockSection(Section
);
669 DPRINT("Address 0x%.8X\n", Address
);
670 return(STATUS_SUCCESS
);
674 * Map anonymous memory for BSS sections
676 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
678 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
679 if (!NT_SUCCESS(Status
))
681 MmUnlockSectionSegment(Segment
);
682 MmUnlockSection(Section
);
683 MmUnlockAddressSpace(AddressSpace
);
684 MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
685 MmLockAddressSpace(AddressSpace
);
686 MmLockSection(Section
);
687 MmLockSectionSegment(Segment
);
690 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
692 MemoryArea
->Attributes
,
695 MmInsertRmap(Page
, PsGetCurrentProcess(),
696 (PVOID
)PAGE_ROUND_DOWN(Address
));
699 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
703 * Cleanup and release locks
705 PageOp
->Status
= STATUS_SUCCESS
;
706 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
707 MmReleasePageOp(PageOp
);
708 MmUnlockSectionSegment(Segment
);
709 MmUnlockSection(Section
);
710 DPRINT("Address 0x%.8X\n", Address
);
711 return(STATUS_SUCCESS
);
715 * Check if this page needs to be mapped COW
717 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
718 (MemoryArea
->Attributes
== PAGE_READWRITE
||
719 MemoryArea
->Attributes
== PAGE_EXECUTE_READWRITE
))
721 Attributes
= PAGE_READONLY
;
725 Attributes
= MemoryArea
->Attributes
;
729 * Get the entry corresponding to the offset within the section
731 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
.u
.LowPart
);
736 * If the entry is zero (and it can't change because we have
737 * locked the segment) then we need to load the page.
741 * Release all our locks and read in the page from disk
743 MmUnlockSectionSegment(Segment
);
744 MmUnlockSection(Section
);
745 MmUnlockAddressSpace(AddressSpace
);
747 if (Segment
->Flags
& MM_PAGEFILE_SECTION
)
749 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
753 Status
= MiReadPage(MemoryArea
, &Offset
, &Page
);
755 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
758 * FIXME: What do we know in this case?
760 DPRINT1("IoPageRead failed (Status %x)\n", Status
);
763 * Cleanup and release locks
765 PageOp
->Status
= Status
;
766 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
767 MmReleasePageOp(PageOp
);
768 MmLockAddressSpace(AddressSpace
);
773 * Relock the address space, section and segment
775 MmLockAddressSpace(AddressSpace
);
776 MmLockSection(Section
);
777 MmLockSectionSegment(Segment
);
780 * Check the entry. No one should change the status of a page
781 * that has a pending page-in.
783 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
.QuadPart
);
786 DbgPrint("Someone changed ppte entry while we slept\n");
791 * Mark the offset within the section as having valid, in-memory
795 MmSetPageEntrySectionSegment(Segment
, Offset
.QuadPart
, Entry
);
796 MmSharePageEntrySectionSegment(Segment
, Offset
.QuadPart
);
798 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
803 if (!NT_SUCCESS(Status
))
805 MmUnlockSectionSegment(Segment
);
806 MmUnlockSection(Section
);
807 MmUnlockAddressSpace(AddressSpace
);
808 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
813 if (!NT_SUCCESS(Status
))
817 MmLockAddressSpace(AddressSpace
);
818 MmLockSection(Section
);
819 MmLockSectionSegment(Segment
);
821 MmInsertRmap(Page
, PsGetCurrentProcess(),
822 (PVOID
)PAGE_ROUND_DOWN(Address
));
823 if (!NT_SUCCESS(Status
))
825 DbgPrint("Unable to create virtual mapping\n");
830 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
832 PageOp
->Status
= STATUS_SUCCESS
;
833 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
834 MmReleasePageOp(PageOp
);
835 MmUnlockSectionSegment(Segment
);
836 MmUnlockSection(Section
);
837 DPRINT("MmNotPresentFaultSectionView succeeded\n");
838 return(STATUS_SUCCESS
);
840 else if (IS_SWAP_FROM_SSE(Entry
))
845 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
848 * Release all our locks and read in the page from disk
850 MmUnlockSectionSegment(Segment
);
851 MmUnlockSection(Section
);
852 MmUnlockAddressSpace(AddressSpace
);
854 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
855 if (!NT_SUCCESS(Status
))
860 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
861 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
862 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
863 if (!NT_SUCCESS(Status
))
869 * Relock the address space, section and segment
871 MmLockAddressSpace(AddressSpace
);
872 MmLockSection(Section
);
873 MmLockSectionSegment(Segment
);
876 * Check the entry. No one should change the status of a page
877 * that has a pending page-in.
879 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
.QuadPart
);
882 DbgPrint("Someone changed ppte entry while we slept\n");
887 * Mark the offset within the section as having valid, in-memory
891 MmSetPageEntrySectionSegment(Segment
, Offset
.QuadPart
, Entry
);
892 MmSharePageEntrySectionSegment(Segment
, Offset
.QuadPart
);
895 * Save the swap entry.
897 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
899 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
904 MmInsertRmap(Page
, PsGetCurrentProcess(),
905 (PVOID
)PAGE_ROUND_DOWN(Address
));
906 if (!NT_SUCCESS(Status
))
908 DbgPrint("Unable to create virtual mapping\n");
913 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
915 PageOp
->Status
= STATUS_SUCCESS
;
916 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
917 MmReleasePageOp(PageOp
);
918 MmUnlockSectionSegment(Segment
);
919 MmUnlockSection(Section
);
920 DPRINT("MmNotPresentFaultSectionView succeeded\n");
921 return(STATUS_SUCCESS
);
926 * If the section offset is already in-memory and valid then just
927 * take another reference to the page
930 Page
= (ULONG_PTR
)PAGE_FROM_SSE(Entry
);
931 MmReferencePage(Page
);
932 MmSharePageEntrySectionSegment(Segment
, Offset
.QuadPart
);
934 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
939 MmInsertRmap(Page
, PsGetCurrentProcess(),
940 (PVOID
)PAGE_ROUND_DOWN(Address
));
941 if (!NT_SUCCESS(Status
))
943 DbgPrint("Unable to create virtual mapping\n");
948 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
950 PageOp
->Status
= STATUS_SUCCESS
;
951 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
952 MmReleasePageOp(PageOp
);
953 MmUnlockSectionSegment(Segment
);
954 MmUnlockSection(Section
);
955 return(STATUS_SUCCESS
);
960 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
961 MEMORY_AREA
* MemoryArea
,
965 PMM_SECTION_SEGMENT Segment
;
966 PSECTION_OBJECT Section
;
972 LARGE_INTEGER Offset
;
976 * Check if the page has been paged out or has already been set readwrite
978 if (!MmIsPagePresent(NULL
, Address
) ||
979 MmGetPageProtect(NULL
, Address
) & PAGE_READWRITE
)
981 return(STATUS_SUCCESS
);
985 * Find the offset of the page
987 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
988 Offset
.QuadPart
= (PAddress
- (ULONG
)MemoryArea
->BaseAddress
) +
989 MemoryArea
->Data
.SectionData
.ViewOffset
;
994 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
995 Section
= MemoryArea
->Data
.SectionData
.Section
;
996 MmLockSection(Section
);
997 MmLockSectionSegment(Segment
);
1002 if (MmGetPageEntrySectionSegment(Segment
, Offset
.QuadPart
) == 0)
1004 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1009 * Check if we are doing COW
1011 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1012 (MemoryArea
->Attributes
== PAGE_READWRITE
||
1013 MemoryArea
->Attributes
== PAGE_EXECUTE_READWRITE
)))
1015 MmUnlockSection(Section
);
1016 MmUnlockSectionSegment(Segment
);
1017 return(STATUS_UNSUCCESSFUL
);
1021 * Get or create a pageop
1023 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
.u
.LowPart
,
1024 MM_PAGEOP_ACCESSFAULT
);
1027 DPRINT1("MmGetPageOp failed\n");
1032 * Wait for any other operations to complete
1034 if (PageOp
->Thread
!= PsGetCurrentThread())
1036 MmUnlockSectionSegment(Segment
);
1037 MmUnlockSection(Section
);
1038 MmUnlockAddressSpace(AddressSpace
);
1039 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
1045 * Check for various strange conditions
1047 if (Status
!= STATUS_SUCCESS
)
1049 DPRINT1("Failed to wait for page op\n");
1052 if (PageOp
->Status
== STATUS_PENDING
)
1054 DPRINT1("Woke for page op before completion\n");
1058 * Restart the operation
1060 MmLockAddressSpace(AddressSpace
);
1061 MmReleasePageOp(PageOp
);
1062 return(STATUS_MM_RESTART_OPERATION
);
1066 * Release locks now we have the pageop
1068 MmUnlockSectionSegment(Segment
);
1069 MmUnlockSection(Section
);
1070 MmUnlockAddressSpace(AddressSpace
);
1075 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1080 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1082 NewAddress
= ExAllocatePageWithPhysPage((ULONG
)NewPage
);
1083 memcpy(NewAddress
, (PVOID
)PAGE_ROUND_DOWN(Address
), PAGESIZE
);
1084 ExUnmapPage(NewAddress
);
1087 * Delete the old entry.
1089 MmDeleteVirtualMapping(PsGetCurrentProcess(), Address
, FALSE
, NULL
, NULL
);
1092 * Set the PTE to point to the new page
1094 MmLockAddressSpace(AddressSpace
);
1095 Status
= MmCreateVirtualMapping(PsGetCurrentProcess(),
1097 MemoryArea
->Attributes
,
1100 MmInsertRmap(NewPage
, PsGetCurrentProcess(),
1101 (PVOID
)PAGE_ROUND_DOWN(Address
));
1102 if (!NT_SUCCESS(Status
))
1104 DbgPrint("Unable to create virtual mapping\n");
1109 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
1113 * Unshare the old page.
1115 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
.QuadPart
, FALSE
);
1116 MmDeleteRmap(OldPage
, PsGetCurrentProcess(),
1117 (PVOID
)PAGE_ROUND_DOWN(Address
));
1118 MmDereferencePage(OldPage
);
1120 PageOp
->Status
= STATUS_SUCCESS
;
1121 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1122 MmReleasePageOp(PageOp
);
1123 return(STATUS_SUCCESS
);
1127 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1129 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1131 ULONG_PTR PhysicalAddress
;
1133 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1134 MmDeleteVirtualMapping(Process
,
1138 (PULONG_PTR
)&PhysicalAddress
);
1141 PageOutContext
->WasDirty
= TRUE
;
1143 if (!PageOutContext
->Private
)
1145 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1146 PageOutContext
->Segment
,
1147 PageOutContext
->Offset
.u
.LowPart
,
1148 PageOutContext
->WasDirty
);
1150 MmDereferencePage(PhysicalAddress
);
1154 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1155 MEMORY_AREA
* MemoryArea
,
1159 LARGE_INTEGER Offset
;
1160 PSECTION_OBJECT Section
;
1161 PMM_SECTION_SEGMENT Segment
;
1162 ULONG_PTR PhysicalAddress
;
1163 MM_SECTION_PAGEOUT_CONTEXT Context
;
1164 SWAPENTRY SwapEntry
;
1169 PFILE_OBJECT FileObject
;
1170 PREACTOS_COMMON_FCB_HEADER Fcb
;
1171 BOOLEAN DirectMapped
;
1173 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1175 Offset
.QuadPart
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
) +
1176 MemoryArea
->Data
.SectionData
.ViewOffset
;
1178 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
1179 DirectMapped
= FALSE
;
1180 if (FileObject
!= NULL
)
1182 Fcb
= (PREACTOS_COMMON_FCB_HEADER
)FileObject
->FsContext
;
1185 * If the file system is letting us go directly to the cache and the
1186 * memory area was mapped at an offset in the file which is page aligned
1187 * then note this is a direct mapped page.
1189 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1190 (Offset
.QuadPart
% PAGESIZE
) == 0)
1192 DirectMapped
= TRUE
;
1197 * Get the segment and section.
1199 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1200 Section
= MemoryArea
->Data
.SectionData
.Section
;
1203 * This should never happen since mappings of physical memory are never
1204 * placed in the rmap lists.
1206 if (Section
->Flags
& SO_PHYSICAL_MEMORY
)
1208 DPRINT1("Trying to page out from physical memory section address 0x%X "
1209 "process %d\n", Address
, AddressSpace
->Process
->UniqueProcessId
);
1214 * Get the section segment entry and the physical address.
1216 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
.QuadPart
);
1217 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1219 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1220 AddressSpace
->Process
->UniqueProcessId
, Address
);
1224 MmGetPhysicalAddressForProcess(AddressSpace
->Process
,
1226 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1229 * Prepare the context structure for the rmap delete call.
1231 Context
.Section
= Section
;
1232 Context
.Segment
= Segment
;
1233 Context
.Offset
= Offset
;
1234 Context
.WasDirty
= FALSE
;
1235 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1236 IS_SWAP_FROM_SSE(Entry
) ||
1237 (ULONG_PTR
)(PAGE_FROM_SSE(Entry
)) != PhysicalAddress
)
1239 Context
.Private
= Private
= TRUE
;
1243 Context
.Private
= Private
= FALSE
;
1247 * Take an additional reference to the page.
1249 MmReferencePage(PhysicalAddress
);
1252 * Paging out data mapped read-only is easy.
1254 if (MemoryArea
->Attributes
& PAGE_READONLY
||
1255 MemoryArea
->Attributes
& PAGE_EXECUTE_READ
)
1258 * Read-only data should never be in the swapfile.
1262 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1263 "paddress 0x%.8X\n", SwapEntry
, Address
,
1269 * Read-only data should never be COWed
1273 DPRINT1("Had private copy of read-only page.\n");
1278 * Delete all mappings of this page.
1280 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
,
1281 MmPageOutDeleteMapping
);
1282 if (Context
.WasDirty
)
1287 * If this page wasn't direct mapped then we have a private copy so
1288 * release back to the system; otherwise the cache manager will have
1289 * handled freeing the cache segment which we mapped from.
1293 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1296 PageOp
->Status
= STATUS_SUCCESS
;
1297 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1298 MmReleasePageOp(PageOp
);
1299 return(STATUS_SUCCESS
);
1303 * Otherwise we have read-write data.
1305 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1308 * If this wasn't a private page then we should have reduced the entry to
1309 * zero by deleting all the rmaps.
1311 if (!Private
&& MmGetPageEntrySectionSegment(Segment
, Offset
.QuadPart
) != 0)
1317 * If the page wasn't dirty then we can just free it as for a readonly page.
1318 * Since we unmapped all the mappings above we know it will not suddenly
1321 if (!Context
.WasDirty
)
1323 if (!DirectMapped
|| Private
)
1325 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1326 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1330 if (!(Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
) &&
1333 DPRINT1("Private page, non-dirty but not swapped out "
1334 "process %d address 0x%.8X\n",
1335 AddressSpace
->Process
->UniqueProcessId
,
1341 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1344 if (!NT_SUCCESS(Status
))
1351 PageOp
->Status
= STATUS_SUCCESS
;
1352 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1353 MmReleasePageOp(PageOp
);
1354 return(STATUS_SUCCESS
);
1358 * If this page was direct mapped from the cache then the cache manager
1359 * will already have taken care of writing it back.
1361 if (DirectMapped
&& !Private
)
1363 assert(SwapEntry
== 0);
1364 MmDereferencePage(PhysicalAddress
);
1365 PageOp
->Status
= STATUS_SUCCESS
;
1366 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1367 MmReleasePageOp(PageOp
);
1368 return(STATUS_SUCCESS
);
1372 * If necessary, allocate an entry in the paging file for this page
1374 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1377 SwapEntry
= MmAllocSwapPage();
1381 * For private pages restore the old mappings.
1385 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1387 MemoryArea
->Attributes
,
1388 (ULONG
)PhysicalAddress
,
1390 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1391 MmInsertRmap(PhysicalAddress
,
1392 MemoryArea
->Process
,
1398 * For non-private pages if the page wasn't direct mapped then
1399 * set it back into the section segment entry so we don't loose
1400 * our copy. Otherwise it will be handled by the cache manager.
1402 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1404 MemoryArea
->Attributes
,
1405 (ULONG
)PhysicalAddress
,
1407 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1408 MmInsertRmap(PhysicalAddress
,
1409 MemoryArea
->Process
,
1411 MmSetPageEntrySectionSegment(Segment
, Offset
.QuadPart
,
1412 (ULONG
)PhysicalAddress
);
1413 MmSharePageEntrySectionSegment(Segment
, Offset
.QuadPart
);
1415 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1416 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1417 MmReleasePageOp(PageOp
);
1418 return(STATUS_UNSUCCESSFUL
);
1423 * Write the page to the pagefile
1425 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
1426 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1427 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1428 if (!NT_SUCCESS(Status
))
1430 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1433 * As above: undo our actions.
1434 * FIXME: Also free the swap page.
1438 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1440 MemoryArea
->Attributes
,
1441 (ULONG
)PhysicalAddress
,
1443 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1444 MmInsertRmap(PhysicalAddress
,
1445 MemoryArea
->Process
,
1450 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1452 MemoryArea
->Attributes
,
1453 (ULONG
)PhysicalAddress
,
1455 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1456 MmInsertRmap(PhysicalAddress
,
1457 MemoryArea
->Process
,
1459 MmSetPageEntrySectionSegment(Segment
, Offset
.QuadPart
,
1460 (ULONG
)PhysicalAddress
);
1461 MmSharePageEntrySectionSegment(Segment
, Offset
.QuadPart
);
1463 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1464 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1465 MmReleasePageOp(PageOp
);
1466 return(STATUS_UNSUCCESSFUL
);
1470 * Otherwise we have succeeded.
1472 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1473 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1474 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1478 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1481 if (!NT_SUCCESS(Status
))
1488 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1489 MmSetPageEntrySectionSegment(Segment
, Offset
.QuadPart
, Entry
);
1492 PageOp
->Status
= STATUS_SUCCESS
;
1493 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1494 MmReleasePageOp(PageOp
);
1495 return(STATUS_SUCCESS
);
1499 MmpDeleteSection(PVOID ObjectBody
)
1501 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
1503 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
1504 if (Section
->Flags
& MM_IMAGE_SECTION
)
1508 for (i
= 0; i
< Section
->NrSegments
; i
++)
1510 InterlockedDecrement(&Section
->Segments
[i
].ReferenceCount
);
1515 InterlockedDecrement(&Section
->Segments
->ReferenceCount
);
1517 if (Section
->FileObject
!= NULL
)
1519 ObDereferenceObject(Section
->FileObject
);
1520 Section
->FileObject
= NULL
;
1525 MmpCloseSection(PVOID ObjectBody
,
1528 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
1529 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
1534 MmpCreateSection(PVOID ObjectBody
,
1536 PWSTR RemainingPath
,
1537 POBJECT_ATTRIBUTES ObjectAttributes
)
1539 DPRINT("MmpCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
1540 ObjectBody
, Parent
, RemainingPath
);
1542 if (RemainingPath
== NULL
)
1544 return(STATUS_SUCCESS
);
1547 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
1549 return(STATUS_UNSUCCESSFUL
);
1552 return(STATUS_SUCCESS
);
1556 MmCreatePhysicalMemorySection(VOID
)
1558 HANDLE PhysSectionH
;
1559 PSECTION_OBJECT PhysSection
;
1561 OBJECT_ATTRIBUTES Obj
;
1562 UNICODE_STRING Name
;
1563 LARGE_INTEGER SectionSize
;
1566 * Create the section mapping physical memory
1568 SectionSize
.QuadPart
= 0xFFFFFFFF;
1569 RtlInitUnicodeString(&Name
, L
"\\Device\\PhysicalMemory");
1570 InitializeObjectAttributes(&Obj
,
1575 Status
= NtCreateSection(&PhysSectionH
,
1579 PAGE_EXECUTE_READWRITE
,
1582 if (!NT_SUCCESS(Status
))
1584 DbgPrint("Failed to create PhysicalMemory section\n");
1587 Status
= ObReferenceObjectByHandle(PhysSectionH
,
1591 (PVOID
*)&PhysSection
,
1593 if (!NT_SUCCESS(Status
))
1595 DbgPrint("Failed to reference PhysicalMemory section\n");
1598 PhysSection
->Flags
= PhysSection
->Flags
| SO_PHYSICAL_MEMORY
;
1599 ObDereferenceObject((PVOID
)PhysSection
);
1601 return(STATUS_SUCCESS
);
1605 MmInitSectionImplementation(VOID
)
1607 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
1609 RtlInitUnicodeString(&MmSectionObjectType
->TypeName
, L
"Section");
1611 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
1612 MmSectionObjectType
->TotalObjects
= 0;
1613 MmSectionObjectType
->TotalHandles
= 0;
1614 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
1615 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
1616 MmSectionObjectType
->PagedPoolCharge
= 0;
1617 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
1618 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
1619 MmSectionObjectType
->Dump
= NULL
;
1620 MmSectionObjectType
->Open
= NULL
;
1621 MmSectionObjectType
->Close
= MmpCloseSection
;
1622 MmSectionObjectType
->Delete
= MmpDeleteSection
;
1623 MmSectionObjectType
->Parse
= NULL
;
1624 MmSectionObjectType
->Security
= NULL
;
1625 MmSectionObjectType
->QueryName
= NULL
;
1626 MmSectionObjectType
->OkayToClose
= NULL
;
1627 MmSectionObjectType
->Create
= MmpCreateSection
;
1628 MmSectionObjectType
->DuplicationNotify
= NULL
;
1630 return(STATUS_SUCCESS
);
1634 MmCreatePageFileSection(PHANDLE SectionHandle
,
1635 ACCESS_MASK DesiredAccess
,
1636 POBJECT_ATTRIBUTES ObjectAttributes
,
1637 PLARGE_INTEGER UMaximumSize
,
1638 ULONG SectionPageProtection
,
1639 ULONG AllocationAttributes
)
1641 * Create a section which is backed by the pagefile
1644 LARGE_INTEGER MaximumSize
;
1645 PSECTION_OBJECT Section
;
1646 PMM_SECTION_SEGMENT Segment
;
1649 if (UMaximumSize
== NULL
)
1651 return(STATUS_UNSUCCESSFUL
);
1653 MaximumSize
= *UMaximumSize
;
1656 * Check the protection
1658 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
1659 SectionPageProtection
)
1661 return(STATUS_INVALID_PAGE_PROTECTION
);
1665 * Create the section
1667 Status
= ObCreateObject(SectionHandle
,
1670 MmSectionObjectType
,
1672 if (!NT_SUCCESS(Status
))
1680 Section
->SectionPageProtection
= SectionPageProtection
;
1681 Section
->AllocateAttributes
= AllocationAttributes
;
1682 InitializeListHead(&Section
->ViewListHead
);
1683 KeInitializeSpinLock(&Section
->ViewListLock
);
1684 KeInitializeMutex(&Section
->Lock
, 0);
1686 Section
->FileObject
= NULL
;
1687 Section
->MaximumSize
= MaximumSize
;
1688 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
1689 TAG_MM_SECTION_SEGMENT
);
1690 if (Segment
== NULL
)
1692 ZwClose(*SectionHandle
);
1693 ObDereferenceObject(Section
);
1694 return(STATUS_NO_MEMORY
);
1696 Section
->Segments
= Segment
;
1697 Segment
->ReferenceCount
= 1;
1698 KeInitializeMutex(&Segment
->Lock
, 0);
1699 Segment
->FileOffset
= 0;
1700 Segment
->Protection
= SectionPageProtection
;
1701 Segment
->Attributes
= AllocationAttributes
;
1702 Segment
->Length
= MaximumSize
.u
.LowPart
;
1703 Segment
->Flags
= MM_PAGEFILE_SECTION
;
1704 Segment
->WriteCopy
= FALSE
;
1705 return(STATUS_SUCCESS
);
1710 MmCreateDataFileSection(PHANDLE SectionHandle
,
1711 ACCESS_MASK DesiredAccess
,
1712 POBJECT_ATTRIBUTES ObjectAttributes
,
1713 PLARGE_INTEGER UMaximumSize
,
1714 ULONG SectionPageProtection
,
1715 ULONG AllocationAttributes
,
1718 * Create a section backed by a data file
1721 PSECTION_OBJECT Section
;
1723 LARGE_INTEGER MaximumSize
;
1724 PFILE_OBJECT FileObject
;
1725 PMM_SECTION_SEGMENT Segment
;
1729 * Check the protection
1731 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
1732 SectionPageProtection
)
1734 return(STATUS_INVALID_PAGE_PROTECTION
);
1738 * Create the section
1740 Status
= ObCreateObject(SectionHandle
,
1743 MmSectionObjectType
,
1745 if (!NT_SUCCESS(Status
))
1753 Section
->SectionPageProtection
= SectionPageProtection
;
1754 Section
->AllocateAttributes
= AllocationAttributes
;
1755 InitializeListHead(&Section
->ViewListHead
);
1756 KeInitializeSpinLock(&Section
->ViewListLock
);
1757 KeInitializeMutex(&Section
->Lock
, 0);
1759 Section
->NrSegments
= 1;
1760 Section
->ImageBase
= NULL
;
1761 Section
->EntryPoint
= NULL
;
1762 Section
->StackReserve
= 0;
1763 Section
->StackCommit
= 0;
1764 Section
->Subsystem
= 0;
1765 Section
->MinorSubsystemVersion
= 0;
1766 Section
->MajorSubsystemVersion
= 0;
1767 Section
->ImageCharacteristics
= 0;
1768 Section
->Machine
= 0;
1769 Section
->Executable
= FALSE
;
1772 * Check file access required
1774 if (SectionPageProtection
& PAGE_READWRITE
||
1775 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
1777 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
1781 FileAccess
= FILE_READ_DATA
;
1785 * Reference the file handle
1787 Status
= ObReferenceObjectByHandle(FileHandle
,
1791 (PVOID
*)&FileObject
,
1793 if (!NT_SUCCESS(Status
))
1795 ZwClose(*SectionHandle
);
1796 ObDereferenceObject(Section
);
1801 * We can't do memory mappings if the file system doesn't support the
1804 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
1806 ZwClose(*SectionHandle
);
1807 ObDereferenceObject(Section
);
1808 ObDereferenceObject(FileObject
);
1809 return(STATUS_INVALID_FILE_FOR_SECTION
);
1813 * FIXME: Revise this once a locking order for file size changes is
1816 if (UMaximumSize
!= NULL
)
1818 MaximumSize
= *UMaximumSize
;
1823 ((PREACTOS_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
1829 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
1834 if (Status
!= STATUS_SUCCESS
)
1836 ZwClose(*SectionHandle
);
1837 ObDereferenceObject(Section
);
1838 ObDereferenceObject(FileObject
);
1843 * If this file hasn't been mapped as a data file before then allocate a
1844 * section segment to describe the data file mapping
1846 if (FileObject
->SectionObjectPointers
->DataSectionObject
== NULL
)
1848 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
1849 TAG_MM_SECTION_SEGMENT
);
1850 if (Segment
== NULL
)
1852 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
1853 ZwClose(*SectionHandle
);
1854 ObDereferenceObject(Section
);
1855 ObDereferenceObject(FileObject
);
1856 return(STATUS_NO_MEMORY
);
1858 Section
->Segments
= Segment
;
1859 Segment
->ReferenceCount
= 1;
1860 KeInitializeMutex(&Segment
->Lock
, 0);
1863 * Set the lock before assigning the segment to the file object
1865 Status
= KeWaitForSingleObject((PVOID
)&Segment
->Lock
,
1870 if (Status
!= STATUS_SUCCESS
)
1872 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
1873 ExFreePool(Segment
);
1874 ZwClose(*SectionHandle
);
1875 ObDereferenceObject(Section
);
1876 ObDereferenceObject(FileObject
);
1879 FileObject
->SectionObjectPointers
->DataSectionObject
= (PVOID
)Segment
;
1881 Segment
->FileOffset
= 0;
1882 Segment
->Protection
= 0;
1883 Segment
->Attributes
= 0;
1885 Segment
->Characteristics
= 0;
1886 Segment
->WriteCopy
= FALSE
;
1887 if (AllocationAttributes
& SEC_RESERVE
)
1889 Segment
->Length
= 0;
1893 Segment
->Length
= MaximumSize
.u
.LowPart
;
1895 Segment
->VirtualAddress
= NULL
;
1900 * If the file is already mapped as a data file then we may need
1904 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointers
->
1906 Section
->Segments
= Segment
;
1907 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
1908 Status
= KeWaitForSingleObject((PVOID
)&Section
->Lock
,
1913 if (Status
!= STATUS_SUCCESS
)
1915 InterlockedDecrement((PLONG
)&Segment
->ReferenceCount
);
1916 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
1917 ZwClose(*SectionHandle
);
1918 ObDereferenceObject(Section
);
1919 ObDereferenceObject(FileObject
);
1922 if (MaximumSize
.u
.LowPart
> Segment
->Length
&&
1923 !(AllocationAttributes
& SEC_RESERVE
))
1925 Segment
->Length
= MaximumSize
.u
.LowPart
;
1928 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
1929 Section
->FileObject
= FileObject
;
1930 KeReleaseMutex(&Segment
->Lock
, FALSE
);
1932 ObDereferenceObject(Section
);
1933 return(STATUS_SUCCESS
);
1936 static ULONG SectionCharacteristicsToProtect
[16] =
1938 PAGE_NOACCESS
, // 0 = NONE
1939 PAGE_NOACCESS
, // 1 = SHARED
1940 PAGE_EXECUTE
, // 2 = EXECUTABLE
1941 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
1942 PAGE_READONLY
, // 4 = READABLE
1943 PAGE_READONLY
, // 5 = READABLE, SHARED
1944 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
1945 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
1946 PAGE_READWRITE
, // 8 = WRITABLE
1947 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
1948 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
1949 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
1950 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
1951 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
1952 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
1953 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
1957 MmCreateImageSection(PHANDLE SectionHandle
,
1958 ACCESS_MASK DesiredAccess
,
1959 POBJECT_ATTRIBUTES ObjectAttributes
,
1960 PLARGE_INTEGER UMaximumSize
,
1961 ULONG SectionPageProtection
,
1962 ULONG AllocationAttributes
,
1965 PSECTION_OBJECT Section
;
1967 PFILE_OBJECT FileObject
;
1969 IMAGE_DOS_HEADER DosHeader
;
1970 IO_STATUS_BLOCK Iosb
;
1971 LARGE_INTEGER Offset
;
1972 IMAGE_NT_HEADERS PEHeader
;
1973 PIMAGE_SECTION_HEADER ImageSections
;
1974 PMM_SECTION_SEGMENT SectionSegments
;
1976 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
1979 * Check the protection
1981 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
1982 SectionPageProtection
)
1984 return(STATUS_INVALID_PAGE_PROTECTION
);
1988 * Specifying a maximum size is meaningless for an image section
1990 if (UMaximumSize
!= NULL
)
1992 return(STATUS_INVALID_PARAMETER_4
);
1996 * Read the dos header
1998 Offset
.QuadPart
= 0;
1999 Status
= ZwReadFile(FileHandle
,
2008 if (!NT_SUCCESS(Status
))
2012 if (Iosb
.Information
!= sizeof(DosHeader
))
2014 return(STATUS_INVALID_IMAGE_FORMAT
);
2018 * Check the DOS signature
2020 if (DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2022 return(STATUS_INVALID_IMAGE_FORMAT
);
2026 * Read the PE header
2028 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2029 Status
= ZwReadFile(FileHandle
,
2038 if (!NT_SUCCESS(Status
))
2042 if (Iosb
.Information
!= sizeof(PEHeader
))
2044 return(STATUS_INVALID_IMAGE_FORMAT
);
2048 * Check the signature
2050 if (PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2052 return(STATUS_INVALID_IMAGE_FORMAT
);
2056 * Read in the section headers
2058 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2060 ExAllocatePool(NonPagedPool
,
2061 PEHeader
.FileHeader
.NumberOfSections
*
2062 sizeof(IMAGE_SECTION_HEADER
));
2063 Status
= ZwReadFile(FileHandle
,
2069 PEHeader
.FileHeader
.NumberOfSections
*
2070 sizeof(IMAGE_SECTION_HEADER
),
2073 if (!NT_SUCCESS(Status
))
2075 ExFreePool(ImageSections
);
2078 if (Iosb
.Information
!=
2079 (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2081 ExFreePool(ImageSections
);
2082 return(STATUS_INVALID_IMAGE_FORMAT
);
2086 * Create the section
2088 Status
= ObCreateObject(SectionHandle
,
2091 MmSectionObjectType
,
2093 if (!NT_SUCCESS(Status
))
2095 ExFreePool(ImageSections
);
2102 Section
->SectionPageProtection
= SectionPageProtection
;
2103 Section
->AllocateAttributes
= AllocationAttributes
;
2104 InitializeListHead(&Section
->ViewListHead
);
2105 KeInitializeSpinLock(&Section
->ViewListLock
);
2106 KeInitializeMutex(&Section
->Lock
, 0);
2107 Section
->Flags
= MM_IMAGE_SECTION
;
2108 Section
->NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2109 Section
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2110 Section
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2111 Section
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2112 Section
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2113 Section
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2114 Section
->MinorSubsystemVersion
=
2115 PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2116 Section
->MajorSubsystemVersion
=
2117 PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2118 Section
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2119 Section
->Machine
= PEHeader
.FileHeader
.Machine
;
2120 Section
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2123 * Check file access required
2125 if (SectionPageProtection
& PAGE_READWRITE
||
2126 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2128 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2132 FileAccess
= FILE_READ_DATA
;
2136 * Reference the file handle
2138 Status
= ObReferenceObjectByHandle(FileHandle
,
2142 (PVOID
*)&FileObject
,
2144 if (!NT_SUCCESS(Status
))
2146 ZwClose(*SectionHandle
);
2147 ObDereferenceObject(Section
);
2148 ExFreePool(ImageSections
);
2153 * We can't do memory mappings if the file system doesn't support the
2156 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2158 ZwClose(*SectionHandle
);
2159 ObDereferenceObject(Section
);
2160 ObDereferenceObject(FileObject
);
2161 ExFreePool(ImageSections
);
2162 return(STATUS_INVALID_FILE_FOR_SECTION
);
2168 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2173 if (Status
!= STATUS_SUCCESS
)
2175 ZwClose(*SectionHandle
);
2176 ObDereferenceObject(Section
);
2177 ObDereferenceObject(FileObject
);
2178 ExFreePool(ImageSections
);
2183 * If this file hasn't been mapped as a image file before then allocate the
2184 * section segments to describe the mapping
2186 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2187 if (FileObject
->SectionObjectPointers
->ImageSectionObject
== NULL
)
2192 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) +
2193 (sizeof(MM_SECTION_SEGMENT
) * NrSegments
);
2194 ImageSectionObject
=
2195 ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2196 if (ImageSectionObject
== NULL
)
2198 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2199 ZwClose(*SectionHandle
);
2200 ObDereferenceObject(Section
);
2201 ObDereferenceObject(FileObject
);
2202 ExFreePool(ImageSections
);
2203 return(STATUS_NO_MEMORY
);
2205 ImageSectionObject
->NrSegments
= NrSegments
;
2206 SectionSegments
= ImageSectionObject
->Segments
;
2207 Section
->Segments
= SectionSegments
;
2209 SectionSegments
[0].FileOffset
= 0;
2210 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2211 SectionSegments
[0].Protection
= PAGE_READWRITE
;
2212 SectionSegments
[0].RawLength
= PAGESIZE
;
2213 SectionSegments
[0].Length
= PAGESIZE
;
2214 SectionSegments
[0].Flags
= 0;
2215 SectionSegments
[0].ReferenceCount
= 1;
2216 SectionSegments
[0].VirtualAddress
= 0;
2217 SectionSegments
[0].WriteCopy
= TRUE
;
2218 KeInitializeMutex(&SectionSegments
[0].Lock
, 0);
2220 for (i
= 1; i
< NrSegments
; i
++)
2222 SectionSegments
[i
].FileOffset
=
2223 ImageSections
[i
-1].PointerToRawData
;
2224 SectionSegments
[i
].Characteristics
=
2225 ImageSections
[i
-1].Characteristics
;
2228 * Set up the protection and write copy variables.
2230 if ((ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_READABLE
) ||
2231 (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_WRITABLE
) ||
2232 (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_EXECUTABLE
))
2234 SectionSegments
[i
].Protection
=
2235 SectionCharacteristicsToProtect
[ImageSections
[i
-1].Characteristics
>> 28];
2236 SectionSegments
[i
].WriteCopy
=
2237 !(ImageSections
[i
- 1].Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2239 else if (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2241 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2242 SectionSegments
[i
].WriteCopy
= TRUE
;
2244 else if (ImageSections
[i
-1].Characteristics
&
2245 IMAGE_SECTION_CHAR_DATA
)
2247 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2248 SectionSegments
[i
].WriteCopy
= TRUE
;
2250 else if (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2252 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2253 SectionSegments
[i
].WriteCopy
= TRUE
;
2257 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2258 SectionSegments
[i
].WriteCopy
= TRUE
;
2262 * Set up the attributes.
2264 if (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2266 SectionSegments
[i
].Attributes
= 0;
2268 else if (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2270 SectionSegments
[i
].Attributes
= 0;
2272 else if (ImageSections
[i
-1].Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2274 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2278 SectionSegments
[i
].Attributes
= 0;
2281 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2282 SectionSegments
[i
].Length
=
2283 ImageSections
[i
-1].Misc
.VirtualSize
;
2284 SectionSegments
[i
].Flags
= 0;
2285 SectionSegments
[i
].ReferenceCount
= 1;
2286 SectionSegments
[i
].VirtualAddress
=
2287 (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2288 KeInitializeMutex(&SectionSegments
[i
].Lock
, 0);
2291 FileObject
->SectionObjectPointers
->ImageSectionObject
=
2292 (PVOID
)ImageSectionObject
;
2298 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)
2299 FileObject
->SectionObjectPointers
->ImageSectionObject
;
2300 SectionSegments
= ImageSectionObject
->Segments
;
2301 Section
->Segments
= SectionSegments
;
2304 * Otherwise just reference all the section segments
2306 for (i
= 0; i
< NrSegments
; i
++)
2308 InterlockedIncrement(&SectionSegments
[i
].ReferenceCount
);
2312 ExFreePool(ImageSections
);
2313 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2314 Section
->FileObject
= FileObject
;
2316 ObDereferenceObject(Section
);
2317 return(STATUS_SUCCESS
);
2321 NtCreateSection (OUT PHANDLE SectionHandle
,
2322 IN ACCESS_MASK DesiredAccess
,
2323 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2324 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
2325 IN ULONG SectionPageProtection OPTIONAL
,
2326 IN ULONG AllocationAttributes
,
2327 IN HANDLE FileHandle OPTIONAL
)
2329 if (AllocationAttributes
& SEC_IMAGE
)
2331 return(MmCreateImageSection(SectionHandle
,
2335 SectionPageProtection
,
2336 AllocationAttributes
,
2339 else if (FileHandle
!= NULL
)
2341 return(MmCreateDataFileSection(SectionHandle
,
2345 SectionPageProtection
,
2346 AllocationAttributes
,
2351 return(MmCreatePageFileSection(SectionHandle
,
2355 SectionPageProtection
,
2356 AllocationAttributes
));
2361 /**********************************************************************
2380 NtOpenSection(PHANDLE SectionHandle
,
2381 ACCESS_MASK DesiredAccess
,
2382 POBJECT_ATTRIBUTES ObjectAttributes
)
2388 Status
= ObOpenObjectByName(ObjectAttributes
,
2389 MmSectionObjectType
,
2400 MmMapViewOfSegment(PEPROCESS Process
,
2401 PMADDRESS_SPACE AddressSpace
,
2402 PSECTION_OBJECT Section
,
2403 PMM_SECTION_SEGMENT Segment
,
2413 MmLockAddressSpace(&Process
->AddressSpace
);
2414 if (Protect
== PAGE_NOACCESS
|| Protect
== PAGE_GUARD
)
2416 DPRINT1("Mapping inaccessible region between 0x%.8X and 0x%.8X\n",
2417 (*BaseAddress
), (*BaseAddress
) + ViewSize
);
2419 Status
= MmCreateMemoryArea(Process
,
2420 &Process
->AddressSpace
,
2421 MEMORY_AREA_SECTION_VIEW_COMMIT
,
2427 MmUnlockAddressSpace(&Process
->AddressSpace
);
2428 if (!NT_SUCCESS(Status
))
2430 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
2431 (*BaseAddress
), (*BaseAddress
) + ViewSize
);
2435 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
2436 InsertTailList(&Section
->ViewListHead
,
2437 &MArea
->Data
.SectionData
.ViewListEntry
);
2438 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
2440 ObReferenceObjectByPointer((PVOID
)Section
,
2443 ExGetPreviousMode());
2444 MArea
->Data
.SectionData
.Segment
= Segment
;
2445 MArea
->Data
.SectionData
.Section
= Section
;
2446 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
2447 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
2449 return(STATUS_SUCCESS
);
2453 /**********************************************************************
2455 * NtMapViewOfSection
2458 * Maps a view of a section into the virtual address space of a
2463 * Handle of the section.
2466 * Handle of the process.
2469 * Desired base address (or NULL) on entry;
2470 * Actual base address of the view on exit.
2473 * Number of high order address bits that must be zero.
2476 * Size in bytes of the initially committed section of
2480 * Offset in bytes from the beginning of the section
2481 * to the beginning of the view.
2484 * Desired length of map (or zero to map all) on entry
2485 * Actual length mapped on exit.
2487 * InheritDisposition
2488 * Specified how the view is to be shared with
2492 * Type of allocation for the pages.
2495 * Protection for the committed region of the view.
2501 NtMapViewOfSection(HANDLE SectionHandle
,
2502 HANDLE ProcessHandle
,
2506 PLARGE_INTEGER SectionOffset
,
2508 SECTION_INHERIT InheritDisposition
,
2509 ULONG AllocationType
,
2512 PSECTION_OBJECT Section
;
2515 PMADDRESS_SPACE AddressSpace
;
2517 Status
= ObReferenceObjectByHandle(ProcessHandle
,
2518 PROCESS_VM_OPERATION
,
2523 if (!NT_SUCCESS(Status
))
2528 AddressSpace
= &Process
->AddressSpace
;
2530 Status
= ObReferenceObjectByHandle(SectionHandle
,
2532 MmSectionObjectType
,
2536 if (!(NT_SUCCESS(Status
)))
2538 DPRINT("ObReference failed rc=%x\n",Status
);
2539 ObDereferenceObject(Process
);
2543 Status
= MmMapViewOfSection(Section
,
2554 ObDereferenceObject(Section
);
2555 ObDereferenceObject(Process
);
2561 MmFreeSectionPage (IN BOOLEAN Before
,
2563 IN PMEMORY_AREA MemoryArea
,
2565 IN ULONG_PTR PhysAddr
,
2566 IN SWAPENTRY SwapEntry
,
2575 MArea
= (PMEMORY_AREA
)Context
;
2579 MmFreeSwapPage(SwapEntry
);
2581 else if (PhysAddr
!= 0)
2586 ((ULONG
)PAGE_ROUND_DOWN(Address
) - (ULONG
)MArea
->BaseAddress
) +
2587 MArea
->Data
.SectionData
.ViewOffset
;
2589 Entry
= MmGetPageEntrySectionSegment(MArea
->Data
.SectionData
.Segment
,
2591 if (IS_SWAP_FROM_SSE(Entry
))
2595 else if (PhysAddr
!= (PAGE_FROM_SSE(Entry
)))
2598 * Just dereference private pages
2600 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
2601 MmDereferencePage(PhysAddr
);
2605 MmUnsharePageEntrySectionSegment(MArea
->Data
.SectionData
.Section
,
2606 MArea
->Data
.SectionData
.Segment
,
2609 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
2610 MmDereferencePage(PhysAddr
);
2616 MmUnmapViewOfSection(PEPROCESS Process
,
2620 PMEMORY_AREA MemoryArea
;
2621 PMADDRESS_SPACE AddressSpace
;
2622 PSECTION_OBJECT Section
;
2623 PMM_SECTION_SEGMENT Segment
;
2626 AddressSpace
= &Process
->AddressSpace
;
2628 DPRINT("Opening memory area Process %x BaseAddress %x\n",
2629 Process
, BaseAddress
);
2630 MmLockAddressSpace(AddressSpace
);
2631 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
2633 if (MemoryArea
== NULL
)
2635 MmUnlockAddressSpace(AddressSpace
);
2636 return(STATUS_UNSUCCESSFUL
);
2639 MmLockSection(MemoryArea
->Data
.SectionData
.Section
);
2640 MmLockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
2641 Section
= MemoryArea
->Data
.SectionData
.Section
;
2642 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2643 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
2644 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
2645 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
2646 if (MemoryArea
->Data
.SectionData
.Section
->Flags
& SO_PHYSICAL_MEMORY
)
2648 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
2656 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
2662 MmUnlockSection(Section
);
2663 MmUnlockSectionSegment(Segment
);
2664 ObDereferenceObject(Section
);
2665 MmUnlockAddressSpace(AddressSpace
);
2666 return(STATUS_SUCCESS
);
2669 /**********************************************************************
2671 * NtUnmapViewOfSection
2687 NtUnmapViewOfSection (HANDLE ProcessHandle
,
2693 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
2694 ProcessHandle
, BaseAddress
);
2696 DPRINT("Referencing process\n");
2697 Status
= ObReferenceObjectByHandle(ProcessHandle
,
2698 PROCESS_VM_OPERATION
,
2703 if (!NT_SUCCESS(Status
))
2705 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
2709 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
2711 ObDereferenceObject(Process
);
2718 NtQuerySection (IN HANDLE SectionHandle
,
2719 IN CINT SectionInformationClass
,
2720 OUT PVOID SectionInformation
,
2722 OUT PULONG ResultLength
)
2724 * FUNCTION: Queries the information of a section object.
2726 * SectionHandle = Handle to the section link object
2727 * SectionInformationClass = Index to a certain information structure
2728 * SectionInformation (OUT)= Caller supplies storage for resulting
2730 * Length = Size of the supplied storage
2731 * ResultLength = Data written
2736 PSECTION_OBJECT Section
;
2739 Status
= ObReferenceObjectByHandle(SectionHandle
,
2741 MmSectionObjectType
,
2745 if (!(NT_SUCCESS(Status
)))
2750 switch (SectionInformationClass
)
2752 case SectionBasicInformation
:
2754 PSECTION_BASIC_INFORMATION Sbi
;
2756 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
2758 ObDereferenceObject(Section
);
2759 return(STATUS_INFO_LENGTH_MISMATCH
);
2762 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
2764 Sbi
->BaseAddress
= 0;
2765 Sbi
->Attributes
= 0;
2766 Sbi
->Size
.QuadPart
= 0;
2768 Status
= STATUS_SUCCESS
;
2773 case SectionImageInformation
:
2775 PSECTION_IMAGE_INFORMATION Sii
;
2777 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
2779 ObDereferenceObject(Section
);
2780 return(STATUS_INFO_LENGTH_MISMATCH
);
2782 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
2783 Sii
->EntryPoint
= Section
->EntryPoint
;
2785 Sii
->StackReserve
= Section
->StackReserve
;
2786 Sii
->StackCommit
= Section
->StackCommit
;
2787 Sii
->Subsystem
= Section
->Subsystem
;
2788 Sii
->MinorSubsystemVersion
= Section
->MinorSubsystemVersion
;
2789 Sii
->MajorSubsystemVersion
= Section
->MajorSubsystemVersion
;
2791 Sii
->Characteristics
= Section
->ImageCharacteristics
;
2792 Sii
->ImageNumber
= Section
->Machine
;
2793 Sii
->Executable
= Section
->Executable
;
2795 Sii
->Unknown4
[0] = 0;
2796 Sii
->Unknown4
[1] = 0;
2797 Sii
->Unknown4
[2] = 0;
2799 Status
= STATUS_SUCCESS
;
2804 Status
= STATUS_INVALID_INFO_CLASS
;
2806 ObDereferenceObject(Section
);
2812 NtExtendSection(IN HANDLE SectionHandle
,
2813 IN ULONG NewMaximumSize
)
2819 /**********************************************************************
2821 * MmAllocateSection@4
2831 * Code taken from ntoskrnl/mm/special.c.
2837 MmAllocateSection (IN ULONG Length
)
2843 PMADDRESS_SPACE AddressSpace
;
2845 DPRINT("MmAllocateSection(Length %x)\n",Length
);
2847 AddressSpace
= MmGetKernelAddressSpace();
2849 MmLockAddressSpace(AddressSpace
);
2850 Status
= MmCreateMemoryArea (NULL
,
2858 if (!NT_SUCCESS(Status
))
2860 MmUnlockAddressSpace(AddressSpace
);
2863 MmUnlockAddressSpace(AddressSpace
);
2864 DPRINT("Result %p\n",Result
);
2865 for (i
= 0; (i
<= (Length
/ PAGESIZE
)); i
++)
2869 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
2870 if (!NT_SUCCESS(Status
))
2872 DbgPrint("Unable to allocate page\n");
2875 Status
= MmCreateVirtualMapping (NULL
,
2876 (Result
+ (i
* PAGESIZE
)),
2880 if (!NT_SUCCESS(Status
))
2882 DbgPrint("Unable to create virtual mapping\n");
2886 return ((PVOID
)Result
);
2890 /**********************************************************************
2892 * MmMapViewOfSection
2895 * Maps a view of a section into the virtual address space of a
2900 * Pointer to the section object.
2903 * Pointer to the process.
2906 * Desired base address (or NULL) on entry;
2907 * Actual base address of the view on exit.
2910 * Number of high order address bits that must be zero.
2913 * Size in bytes of the initially committed section of
2917 * Offset in bytes from the beginning of the section
2918 * to the beginning of the view.
2921 * Desired length of map (or zero to map all) on entry
2922 * Actual length mapped on exit.
2924 * InheritDisposition
2925 * Specified how the view is to be shared with
2929 * Type of allocation for the pages.
2932 * Protection for the committed region of the view.
2938 MmMapViewOfSection(IN PVOID SectionObject
,
2939 IN PEPROCESS Process
,
2940 IN OUT PVOID
*BaseAddress
,
2942 IN ULONG CommitSize
,
2943 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
2944 IN OUT PULONG ViewSize
,
2945 IN SECTION_INHERIT InheritDisposition
,
2946 IN ULONG AllocationType
,
2949 PSECTION_OBJECT Section
;
2950 PMADDRESS_SPACE AddressSpace
;
2954 Section
= (PSECTION_OBJECT
)SectionObject
;
2955 AddressSpace
= &Process
->AddressSpace
;
2957 MmLockAddressSpace(AddressSpace
);
2958 MmLockSection(SectionObject
);
2960 if (Section
->Flags
& MM_IMAGE_SECTION
)
2964 for (i
= 0; i
< Section
->NrSegments
; i
++)
2968 if (!(Section
->Segments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
2970 SBaseAddress
= (PVOID
)
2971 ((ULONG
)Section
->ImageBase
+
2972 (ULONG
)Section
->Segments
[i
].VirtualAddress
);
2974 MmLockSectionSegment(&Section
->Segments
[i
]);
2975 Status
= MmMapViewOfSegment(Process
,
2976 &Process
->AddressSpace
,
2978 &Section
->Segments
[i
],
2980 Section
->Segments
[i
].Length
,
2981 Section
->Segments
[i
].Protection
,
2982 Section
->Segments
[i
].FileOffset
);
2983 MmUnlockSectionSegment(&Section
->Segments
[i
]);
2984 if (!NT_SUCCESS(Status
))
2986 MmUnlockSection(Section
);
2987 MmUnlockAddressSpace(AddressSpace
);
2992 *BaseAddress
= Section
->ImageBase
;
2996 if (SectionOffset
== NULL
)
3002 ViewOffset
= SectionOffset
->u
.LowPart
;
3005 if ((ViewOffset
% PAGESIZE
) != 0)
3007 MmUnlockSection(Section
);
3008 MmUnlockAddressSpace(AddressSpace
);
3009 return(STATUS_MAPPED_ALIGNMENT
);
3012 if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3014 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3017 MmLockSectionSegment(Section
->Segments
);
3018 Status
= MmMapViewOfSegment(Process
,
3019 &Process
->AddressSpace
,
3026 MmUnlockSectionSegment(Section
->Segments
);
3027 if (!NT_SUCCESS(Status
))
3029 MmUnlockSection(Section
);
3030 MmUnlockAddressSpace(AddressSpace
);
3035 MmUnlockSection(Section
);
3036 MmUnlockAddressSpace(AddressSpace
);
3038 return(STATUS_SUCCESS
);
3043 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3044 IN PLARGE_INTEGER NewFileSize
)
3052 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
3059 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3060 IN MMFLUSH_TYPE FlushType
)
3067 MmForceSectionClosed (DWORD Unknown0
,
3076 MmMapViewInSystemSpace (IN PVOID Section
,
3077 OUT PVOID
* MappedBase
,
3081 return (STATUS_NOT_IMPLEMENTED
);
3085 MmUnmapViewInSystemSpace (DWORD Unknown0
)
3088 return (STATUS_NOT_IMPLEMENTED
);
3093 MmSetBankedSection (DWORD Unknown0
,
3101 return (STATUS_NOT_IMPLEMENTED
);
3105 /**********************************************************************
3110 * Creates a section object.
3113 * SectionObjiect (OUT)
3114 * Caller supplied storage for the resulting pointer
3115 * to a SECTION_BOJECT instance;
3118 * Specifies the desired access to the section can be a
3120 * STANDARD_RIGHTS_REQUIRED |
3122 * SECTION_MAP_WRITE |
3123 * SECTION_MAP_READ |
3124 * SECTION_MAP_EXECUTE
3126 * ObjectAttributes [OPTIONAL]
3127 * Initialized attributes for the object can be used
3128 * to create a named section;
3131 * Maximizes the size of the memory section. Must be
3132 * non-NULL for a page-file backed section.
3133 * If value specified for a mapped file and the file is
3134 * not large enough, file will be extended.
3136 * SectionPageProtection
3137 * Can be a combination of:
3143 * AllocationAttributes
3144 * Can be a combination of:
3149 * Handle to a file to create a section mapped to a file
3150 * instead of a memory backed section;
3159 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
3160 IN ACCESS_MASK DesiredAccess
,
3161 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3162 IN PLARGE_INTEGER MaximumSize
,
3163 IN ULONG SectionPageProtection
,
3164 IN ULONG AllocationAttributes
,
3165 IN HANDLE FileHandle OPTIONAL
,
3166 IN PFILE_OBJECT File OPTIONAL
)
3168 return (STATUS_NOT_IMPLEMENTED
);