3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/section.c
22 * PURPOSE: Implements section objects
24 * PROGRAMMERS: Rex Jolliff
37 * Thomas Weidenmueller
38 * Gunnar Andre' Dalsnes
46 /* INCLUDES *****************************************************************/
50 #include <internal/debug.h>
51 #include <reactos/exeformat.h>
53 #if defined (ALLOC_PRAGMA)
54 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
55 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 /* TYPES *********************************************************************/
63 PSECTION_OBJECT Section
;
64 PMM_SECTION_SEGMENT Segment
;
69 MM_SECTION_PAGEOUT_CONTEXT
;
71 /* GLOBALS *******************************************************************/
73 POBJECT_TYPE MmSectionObjectType
= NULL
;
75 static GENERIC_MAPPING MmpSectionMapping
= {
76 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
77 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
78 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
81 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
82 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
83 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
84 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
85 #define MAX_SHARE_COUNT 0x7FF
86 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
87 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
88 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
90 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
92 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
93 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
96 /* FUNCTIONS *****************************************************************/
98 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
101 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
102 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
103 * RETURNS: Status of the wait.
106 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
108 LARGE_INTEGER Timeout
;
109 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
111 Timeout
.QuadPart
= -100000000LL; // 10 sec
114 Timeout
.QuadPart
= -100000000; // 10 sec
117 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
122 * FUNCTION: Sets the page op completion event and releases the page op.
123 * ARGUMENTS: PMM_PAGEOP.
124 * RETURNS: In shorter time than it takes you to even read this
125 * description, so don't even think about geting a mug of coffee.
128 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
130 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
131 MmReleasePageOp(PageOp
);
136 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
137 * ARGUMENTS: PFILE_OBJECT to wait for.
138 * RETURNS: Status of the wait.
141 MmspWaitForFileLock(PFILE_OBJECT File
)
143 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
148 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
151 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
153 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
155 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
157 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
165 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
167 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
169 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
170 PMM_SECTION_SEGMENT SectionSegments
;
174 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
175 NrSegments
= ImageSectionObject
->NrSegments
;
176 SectionSegments
= ImageSectionObject
->Segments
;
177 for (i
= 0; i
< NrSegments
; i
++)
179 if (SectionSegments
[i
].ReferenceCount
!= 0)
181 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
182 SectionSegments
[i
].ReferenceCount
);
185 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
187 ExFreePool(ImageSectionObject
->Segments
);
188 ExFreePool(ImageSectionObject
);
189 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
191 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
193 PMM_SECTION_SEGMENT Segment
;
195 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
198 if (Segment
->ReferenceCount
!= 0)
200 DPRINT1("Data segment still referenced\n");
203 MmFreePageTablesSectionSegment(Segment
);
205 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
211 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
213 ExAcquireFastMutex(&Segment
->Lock
);
218 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
220 ExReleaseFastMutex(&Segment
->Lock
);
225 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
229 PSECTION_PAGE_TABLE Table
;
230 ULONG DirectoryOffset
;
233 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
235 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
239 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
240 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
244 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
245 ExAllocatePoolWithTag(PagedPool
, sizeof(SECTION_PAGE_TABLE
),
246 TAG_SECTION_PAGE_TABLE
);
251 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
252 DPRINT("Table %x\n", Table
);
255 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
256 Table
->Entry
[TableOffset
] = Entry
;
262 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
265 PSECTION_PAGE_TABLE Table
;
267 ULONG DirectoryOffset
;
270 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
272 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
274 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
278 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
279 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
280 DPRINT("Table %x\n", Table
);
286 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
287 Entry
= Table
->Entry
[TableOffset
];
293 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
298 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
301 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
304 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
306 DPRINT1("Maximum share count reached\n");
309 if (IS_SWAP_FROM_SSE(Entry
))
313 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
314 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
319 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
320 PMM_SECTION_SEGMENT Segment
,
326 BOOLEAN IsDirectMapped
= FALSE
;
328 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
331 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
334 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
336 DPRINT1("Zero share count for unshare\n");
339 if (IS_SWAP_FROM_SSE(Entry
))
343 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
345 * If we reducing the share count of this entry to zero then set the entry
346 * to zero and tell the cache the page is no longer mapped.
348 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
350 PFILE_OBJECT FileObject
;
352 SWAPENTRY SavedSwapEntry
;
354 BOOLEAN IsImageSection
;
357 FileOffset
= Offset
+ Segment
->FileOffset
;
359 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
361 Page
= PFN_FROM_SSE(Entry
);
362 FileObject
= Section
->FileObject
;
363 if (FileObject
!= NULL
&&
364 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
367 if ((FileOffset
% PAGE_SIZE
) == 0 &&
368 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
371 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
372 IsDirectMapped
= TRUE
;
373 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
374 if (!NT_SUCCESS(Status
))
376 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
382 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
383 if (SavedSwapEntry
== 0)
386 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
387 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
391 * Try to page out this page and set the swap entry
392 * within the section segment. There exist no rmap entry
393 * for this page. The pager thread can't page out a
394 * page without a rmap entry.
396 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
400 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
403 MmReleasePageMemoryConsumer(MC_USER
, Page
);
409 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
410 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
418 * We hold all locks. Nobody can do something with the current
419 * process and the current segment (also not within an other process).
422 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
423 if (!NT_SUCCESS(Status
))
425 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
429 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
430 MmSetSavedSwapEntryPage(Page
, 0);
432 MmReleasePageMemoryConsumer(MC_USER
, Page
);
436 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
443 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
445 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
448 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
451 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
454 PCACHE_SEGMENT CacheSeg
;
455 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
456 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
459 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
468 MiReadPage(PMEMORY_AREA MemoryArea
,
472 * FUNCTION: Read a page for a section backed memory area.
474 * MemoryArea - Memory area to read the page for.
475 * Offset - Offset of the page to read.
476 * Page - Variable that receives a page contains the read data.
483 PCACHE_SEGMENT CacheSeg
;
484 PFILE_OBJECT FileObject
;
488 BOOLEAN IsImageSection
;
491 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
492 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
493 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
494 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
495 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
499 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
502 * If the file system is letting us go directly to the cache and the
503 * memory area was mapped at an offset in the file which is page aligned
504 * then get the related cache segment.
506 if ((FileOffset
% PAGE_SIZE
) == 0 &&
507 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
508 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
512 * Get the related cache segment; we use a lower level interface than
513 * filesystems do because it is safe for us to use an offset with a
514 * alignment less than the file system block size.
516 Status
= CcRosGetCacheSegment(Bcb
,
522 if (!NT_SUCCESS(Status
))
529 * If the cache segment isn't up to date then call the file
530 * system to read in the data.
532 Status
= ReadCacheSegment(CacheSeg
);
533 if (!NT_SUCCESS(Status
))
535 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
540 * Retrieve the page from the cache segment that we actually want.
542 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
543 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
545 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
550 ULONG CacheSegOffset
;
552 * Allocate a page, this is rather complicated by the possibility
553 * we might have to move other things out of memory
555 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
556 if (!NT_SUCCESS(Status
))
560 Status
= CcRosGetCacheSegment(Bcb
,
566 if (!NT_SUCCESS(Status
))
573 * If the cache segment isn't up to date then call the file
574 * system to read in the data.
576 Status
= ReadCacheSegment(CacheSeg
);
577 if (!NT_SUCCESS(Status
))
579 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
583 PageAddr
= MmCreateHyperspaceMapping(*Page
);
584 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
585 Length
= RawLength
- SegOffset
;
586 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
588 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
590 else if (CacheSegOffset
>= PAGE_SIZE
)
592 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
596 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
597 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
598 Status
= CcRosGetCacheSegment(Bcb
,
599 FileOffset
+ CacheSegOffset
,
604 if (!NT_SUCCESS(Status
))
606 MmDeleteHyperspaceMapping(PageAddr
);
612 * If the cache segment isn't up to date then call the file
613 * system to read in the data.
615 Status
= ReadCacheSegment(CacheSeg
);
616 if (!NT_SUCCESS(Status
))
618 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
619 MmDeleteHyperspaceMapping(PageAddr
);
623 if (Length
< PAGE_SIZE
)
625 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
629 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
632 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
633 MmDeleteHyperspaceMapping(PageAddr
);
635 return(STATUS_SUCCESS
);
640 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
641 MEMORY_AREA
* MemoryArea
,
649 PSECTION_OBJECT Section
;
650 PMM_SECTION_SEGMENT Segment
;
659 * There is a window between taking the page fault and locking the
660 * address space when another thread could load the page so we check
663 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
667 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
669 return(STATUS_SUCCESS
);
672 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
673 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
674 + MemoryArea
->Data
.SectionData
.ViewOffset
;
676 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
677 Section
= MemoryArea
->Data
.SectionData
.Section
;
678 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
679 &MemoryArea
->Data
.SectionData
.RegionListHead
,
684 MmLockSectionSegment(Segment
);
687 * Check if this page needs to be mapped COW
689 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
690 (Region
->Protect
== PAGE_READWRITE
||
691 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
693 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
697 Attributes
= Region
->Protect
;
701 * Get or create a page operation descriptor
703 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
706 DPRINT1("MmGetPageOp failed\n");
711 * Check if someone else is already handling this fault, if so wait
714 if (PageOp
->Thread
!= PsGetCurrentThread())
716 MmUnlockSectionSegment(Segment
);
717 MmUnlockAddressSpace(AddressSpace
);
718 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
720 * Check for various strange conditions
722 if (Status
!= STATUS_SUCCESS
)
724 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
727 if (PageOp
->Status
== STATUS_PENDING
)
729 DPRINT1("Woke for page op before completion\n");
732 MmLockAddressSpace(AddressSpace
);
734 * If this wasn't a pagein then restart the operation
736 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
738 MmspCompleteAndReleasePageOp(PageOp
);
739 DPRINT("Address 0x%.8X\n", Address
);
740 return(STATUS_MM_RESTART_OPERATION
);
744 * If the thread handling this fault has failed then we don't retry
746 if (!NT_SUCCESS(PageOp
->Status
))
748 Status
= PageOp
->Status
;
749 MmspCompleteAndReleasePageOp(PageOp
);
750 DPRINT("Address 0x%.8X\n", Address
);
753 MmLockSectionSegment(Segment
);
755 * If the completed fault was for another address space then set the
758 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
760 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
761 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
763 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
766 * The page was a private page in another or in our address space
768 MmUnlockSectionSegment(Segment
);
769 MmspCompleteAndReleasePageOp(PageOp
);
770 return(STATUS_MM_RESTART_OPERATION
);
773 Page
= PFN_FROM_SSE(Entry
);
775 MmSharePageEntrySectionSegment(Segment
, Offset
);
777 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
778 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
780 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
785 if (!NT_SUCCESS(Status
))
787 DbgPrint("Unable to create virtual mapping\n");
790 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
796 MmUnlockSectionSegment(Segment
);
797 PageOp
->Status
= STATUS_SUCCESS
;
798 MmspCompleteAndReleasePageOp(PageOp
);
799 DPRINT("Address 0x%.8X\n", Address
);
800 return(STATUS_SUCCESS
);
803 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
807 * Must be private page we have swapped out.
814 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
816 DPRINT1("Found a swaped out private page in a pagefile section.\n");
820 MmUnlockSectionSegment(Segment
);
821 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
823 MmUnlockAddressSpace(AddressSpace
);
824 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
825 if (!NT_SUCCESS(Status
))
830 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
831 if (!NT_SUCCESS(Status
))
833 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
836 MmLockAddressSpace(AddressSpace
);
837 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
842 if (!NT_SUCCESS(Status
))
844 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
850 * Store the swap entry for later use.
852 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
855 * Add the page to the process's working set
857 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
860 * Finish the operation
866 PageOp
->Status
= STATUS_SUCCESS
;
867 MmspCompleteAndReleasePageOp(PageOp
);
868 DPRINT("Address 0x%.8X\n", Address
);
869 return(STATUS_SUCCESS
);
873 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
875 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
877 MmUnlockSectionSegment(Segment
);
879 * Just map the desired physical page
881 Page
= Offset
>> PAGE_SHIFT
;
882 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
887 if (!NT_SUCCESS(Status
))
889 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
894 * Don't add an rmap entry since the page mapped could be for
899 MmLockPageUnsafe(Page
);
903 * Cleanup and release locks
905 PageOp
->Status
= STATUS_SUCCESS
;
906 MmspCompleteAndReleasePageOp(PageOp
);
907 DPRINT("Address 0x%.8X\n", Address
);
908 return(STATUS_SUCCESS
);
912 * Map anonymous memory for BSS sections
914 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
916 MmUnlockSectionSegment(Segment
);
917 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
918 if (!NT_SUCCESS(Status
))
920 MmUnlockAddressSpace(AddressSpace
);
921 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
922 MmLockAddressSpace(AddressSpace
);
924 if (!NT_SUCCESS(Status
))
928 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
933 if (!NT_SUCCESS(Status
))
935 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
939 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
946 * Cleanup and release locks
948 PageOp
->Status
= STATUS_SUCCESS
;
949 MmspCompleteAndReleasePageOp(PageOp
);
950 DPRINT("Address 0x%.8X\n", Address
);
951 return(STATUS_SUCCESS
);
955 * Get the entry corresponding to the offset within the section
957 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
962 * If the entry is zero (and it can't change because we have
963 * locked the segment) then we need to load the page.
967 * Release all our locks and read in the page from disk
969 MmUnlockSectionSegment(Segment
);
970 MmUnlockAddressSpace(AddressSpace
);
972 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
973 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
975 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
976 if (!NT_SUCCESS(Status
))
978 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
983 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
984 if (!NT_SUCCESS(Status
))
986 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
989 if (!NT_SUCCESS(Status
))
992 * FIXME: What do we know in this case?
995 * Cleanup and release locks
997 MmLockAddressSpace(AddressSpace
);
998 PageOp
->Status
= Status
;
999 MmspCompleteAndReleasePageOp(PageOp
);
1000 DPRINT("Address 0x%.8X\n", Address
);
1004 * Relock the address space and segment
1006 MmLockAddressSpace(AddressSpace
);
1007 MmLockSectionSegment(Segment
);
1010 * Check the entry. No one should change the status of a page
1011 * that has a pending page-in.
1013 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1014 if (Entry
!= Entry1
)
1016 DbgPrint("Someone changed ppte entry while we slept\n");
1021 * Mark the offset within the section as having valid, in-memory
1024 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1025 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1026 MmUnlockSectionSegment(Segment
);
1028 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1033 if (!NT_SUCCESS(Status
))
1035 DbgPrint("Unable to create virtual mapping\n");
1038 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1044 PageOp
->Status
= STATUS_SUCCESS
;
1045 MmspCompleteAndReleasePageOp(PageOp
);
1046 DPRINT("Address 0x%.8X\n", Address
);
1047 return(STATUS_SUCCESS
);
1049 else if (IS_SWAP_FROM_SSE(Entry
))
1051 SWAPENTRY SwapEntry
;
1053 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1056 * Release all our locks and read in the page from disk
1058 MmUnlockSectionSegment(Segment
);
1060 MmUnlockAddressSpace(AddressSpace
);
1062 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1063 if (!NT_SUCCESS(Status
))
1068 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1069 if (!NT_SUCCESS(Status
))
1075 * Relock the address space and segment
1077 MmLockAddressSpace(AddressSpace
);
1078 MmLockSectionSegment(Segment
);
1081 * Check the entry. No one should change the status of a page
1082 * that has a pending page-in.
1084 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1085 if (Entry
!= Entry1
)
1087 DbgPrint("Someone changed ppte entry while we slept\n");
1092 * Mark the offset within the section as having valid, in-memory
1095 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1096 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1097 MmUnlockSectionSegment(Segment
);
1100 * Save the swap entry.
1102 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1103 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1108 if (!NT_SUCCESS(Status
))
1110 DbgPrint("Unable to create virtual mapping\n");
1113 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1118 PageOp
->Status
= STATUS_SUCCESS
;
1119 MmspCompleteAndReleasePageOp(PageOp
);
1120 DPRINT("Address 0x%.8X\n", Address
);
1121 return(STATUS_SUCCESS
);
1126 * If the section offset is already in-memory and valid then just
1127 * take another reference to the page
1130 Page
= PFN_FROM_SSE(Entry
);
1132 MmSharePageEntrySectionSegment(Segment
, Offset
);
1133 MmUnlockSectionSegment(Segment
);
1135 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1140 if (!NT_SUCCESS(Status
))
1142 DbgPrint("Unable to create virtual mapping\n");
1145 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1150 PageOp
->Status
= STATUS_SUCCESS
;
1151 MmspCompleteAndReleasePageOp(PageOp
);
1152 DPRINT("Address 0x%.8X\n", Address
);
1153 return(STATUS_SUCCESS
);
1159 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1160 MEMORY_AREA
* MemoryArea
,
1164 PMM_SECTION_SEGMENT Segment
;
1165 PSECTION_OBJECT Section
;
1176 * Check if the page has been paged out or has already been set readwrite
1178 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1179 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1181 DPRINT("Address 0x%.8X\n", Address
);
1182 return(STATUS_SUCCESS
);
1186 * Find the offset of the page
1188 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1189 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1190 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1192 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1193 Section
= MemoryArea
->Data
.SectionData
.Section
;
1194 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1195 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1200 MmLockSectionSegment(Segment
);
1202 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1203 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1205 MmUnlockSectionSegment(Segment
);
1208 * Check if we are doing COW
1210 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1211 (Region
->Protect
== PAGE_READWRITE
||
1212 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1214 DPRINT("Address 0x%.8X\n", Address
);
1215 return(STATUS_UNSUCCESSFUL
);
1218 if (IS_SWAP_FROM_SSE(Entry
) ||
1219 PFN_FROM_SSE(Entry
) != OldPage
)
1221 /* This is a private page. We must only change the page protection. */
1222 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1223 return(STATUS_SUCCESS
);
1227 * Get or create a pageop
1229 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1230 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1233 DPRINT1("MmGetPageOp failed\n");
1238 * Wait for any other operations to complete
1240 if (PageOp
->Thread
!= PsGetCurrentThread())
1242 MmUnlockAddressSpace(AddressSpace
);
1243 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1245 * Check for various strange conditions
1247 if (Status
== STATUS_TIMEOUT
)
1249 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1252 if (PageOp
->Status
== STATUS_PENDING
)
1254 DPRINT1("Woke for page op before completion\n");
1258 * Restart the operation
1260 MmLockAddressSpace(AddressSpace
);
1261 MmspCompleteAndReleasePageOp(PageOp
);
1262 DPRINT("Address 0x%.8X\n", Address
);
1263 return(STATUS_MM_RESTART_OPERATION
);
1267 * Release locks now we have the pageop
1269 MmUnlockAddressSpace(AddressSpace
);
1274 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1275 if (!NT_SUCCESS(Status
))
1283 MiCopyFromUserPage(NewPage
, PAddress
);
1285 MmLockAddressSpace(AddressSpace
);
1287 * Delete the old entry.
1289 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1292 * Set the PTE to point to the new page
1294 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1299 if (!NT_SUCCESS(Status
))
1301 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1305 if (!NT_SUCCESS(Status
))
1307 DbgPrint("Unable to create virtual mapping\n");
1312 MmLockPage(NewPage
);
1313 MmUnlockPage(OldPage
);
1317 * Unshare the old page.
1319 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1320 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1321 MmLockSectionSegment(Segment
);
1322 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1323 MmUnlockSectionSegment(Segment
);
1325 PageOp
->Status
= STATUS_SUCCESS
;
1326 MmspCompleteAndReleasePageOp(PageOp
);
1327 DPRINT("Address 0x%.8X\n", Address
);
1328 return(STATUS_SUCCESS
);
1332 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1334 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1338 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1341 MmLockAddressSpace(&Process
->AddressSpace
);
1344 MmDeleteVirtualMapping(Process
,
1351 PageOutContext
->WasDirty
= TRUE
;
1353 if (!PageOutContext
->Private
)
1355 MmLockSectionSegment(PageOutContext
->Segment
);
1356 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1357 PageOutContext
->Segment
,
1358 PageOutContext
->Offset
,
1359 PageOutContext
->WasDirty
,
1361 MmUnlockSectionSegment(PageOutContext
->Segment
);
1365 MmUnlockAddressSpace(&Process
->AddressSpace
);
1368 if (PageOutContext
->Private
)
1370 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1373 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1378 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1379 MEMORY_AREA
* MemoryArea
,
1384 MM_SECTION_PAGEOUT_CONTEXT Context
;
1385 SWAPENTRY SwapEntry
;
1389 PFILE_OBJECT FileObject
;
1391 BOOLEAN DirectMapped
;
1392 BOOLEAN IsImageSection
;
1394 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1397 * Get the segment and section.
1399 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1400 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1402 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1403 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1404 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1406 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1408 FileObject
= Context
.Section
->FileObject
;
1409 DirectMapped
= FALSE
;
1410 if (FileObject
!= NULL
&&
1411 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1413 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1416 * If the file system is letting us go directly to the cache and the
1417 * memory area was mapped at an offset in the file which is page aligned
1418 * then note this is a direct mapped page.
1420 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1421 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1423 DirectMapped
= TRUE
;
1429 * This should never happen since mappings of physical memory are never
1430 * placed in the rmap lists.
1432 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1434 DPRINT1("Trying to page out from physical memory section address 0x%X "
1435 "process %d\n", Address
,
1436 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1441 * Get the section segment entry and the physical address.
1443 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1444 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1446 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1447 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1450 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1451 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1454 * Prepare the context structure for the rmap delete call.
1456 Context
.WasDirty
= FALSE
;
1457 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1458 IS_SWAP_FROM_SSE(Entry
) ||
1459 PFN_FROM_SSE(Entry
) != Page
)
1461 Context
.Private
= TRUE
;
1465 Context
.Private
= FALSE
;
1469 * Take an additional reference to the page or the cache segment.
1471 if (DirectMapped
&& !Context
.Private
)
1473 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1475 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1481 MmReferencePage(Page
);
1484 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1487 * If this wasn't a private page then we should have reduced the entry to
1488 * zero by deleting all the rmaps.
1490 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1492 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1493 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1500 * If the page wasn't dirty then we can just free it as for a readonly page.
1501 * Since we unmapped all the mappings above we know it will not suddenly
1503 * If the page is from a pagefile section and has no swap entry,
1504 * we can't free the page at this point.
1506 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1507 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1509 if (Context
.Private
)
1511 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1512 Context
.WasDirty
? "dirty" : "clean", Address
);
1515 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1517 MmSetSavedSwapEntryPage(Page
, 0);
1518 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1519 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1520 PageOp
->Status
= STATUS_SUCCESS
;
1521 MmspCompleteAndReleasePageOp(PageOp
);
1522 return(STATUS_SUCCESS
);
1525 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1527 if (Context
.Private
)
1529 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1530 Context
.WasDirty
? "dirty" : "clean", Address
);
1533 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1535 MmSetSavedSwapEntryPage(Page
, 0);
1538 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1540 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1541 PageOp
->Status
= STATUS_SUCCESS
;
1542 MmspCompleteAndReleasePageOp(PageOp
);
1543 return(STATUS_SUCCESS
);
1546 else if (!Context
.Private
&& DirectMapped
)
1550 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1554 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1555 if (!NT_SUCCESS(Status
))
1557 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1560 PageOp
->Status
= STATUS_SUCCESS
;
1561 MmspCompleteAndReleasePageOp(PageOp
);
1562 return(STATUS_SUCCESS
);
1564 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1568 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1572 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1573 PageOp
->Status
= STATUS_SUCCESS
;
1574 MmspCompleteAndReleasePageOp(PageOp
);
1575 return(STATUS_SUCCESS
);
1577 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1579 MmSetSavedSwapEntryPage(Page
, 0);
1580 MmLockAddressSpace(AddressSpace
);
1581 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1584 MmUnlockAddressSpace(AddressSpace
);
1585 if (!NT_SUCCESS(Status
))
1589 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1590 PageOp
->Status
= STATUS_SUCCESS
;
1591 MmspCompleteAndReleasePageOp(PageOp
);
1592 return(STATUS_SUCCESS
);
1596 * If necessary, allocate an entry in the paging file for this page
1600 SwapEntry
= MmAllocSwapPage();
1603 MmShowOutOfSpaceMessagePagingFile();
1604 MmLockAddressSpace(AddressSpace
);
1606 * For private pages restore the old mappings.
1608 if (Context
.Private
)
1610 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1612 MemoryArea
->Protect
,
1615 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1617 AddressSpace
->Process
,
1623 * For non-private pages if the page wasn't direct mapped then
1624 * set it back into the section segment entry so we don't loose
1625 * our copy. Otherwise it will be handled by the cache manager.
1627 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1629 MemoryArea
->Protect
,
1632 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1634 AddressSpace
->Process
,
1636 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1637 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1639 MmUnlockAddressSpace(AddressSpace
);
1640 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1641 MmspCompleteAndReleasePageOp(PageOp
);
1642 return(STATUS_PAGEFILE_QUOTA
);
1647 * Write the page to the pagefile
1649 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1650 if (!NT_SUCCESS(Status
))
1652 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1655 * As above: undo our actions.
1656 * FIXME: Also free the swap page.
1658 MmLockAddressSpace(AddressSpace
);
1659 if (Context
.Private
)
1661 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1663 MemoryArea
->Protect
,
1666 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1668 AddressSpace
->Process
,
1673 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1675 MemoryArea
->Protect
,
1678 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1680 AddressSpace
->Process
,
1682 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1683 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1685 MmUnlockAddressSpace(AddressSpace
);
1686 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1687 MmspCompleteAndReleasePageOp(PageOp
);
1688 return(STATUS_UNSUCCESSFUL
);
1692 * Otherwise we have succeeded.
1694 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1695 MmSetSavedSwapEntryPage(Page
, 0);
1696 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1697 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1699 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1703 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1706 if (Context
.Private
)
1708 MmLockAddressSpace(AddressSpace
);
1709 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1712 MmUnlockAddressSpace(AddressSpace
);
1713 if (!NT_SUCCESS(Status
))
1720 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1721 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1724 PageOp
->Status
= STATUS_SUCCESS
;
1725 MmspCompleteAndReleasePageOp(PageOp
);
1726 return(STATUS_SUCCESS
);
1731 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1732 PMEMORY_AREA MemoryArea
,
1737 PSECTION_OBJECT Section
;
1738 PMM_SECTION_SEGMENT Segment
;
1740 SWAPENTRY SwapEntry
;
1744 PFILE_OBJECT FileObject
;
1746 BOOLEAN DirectMapped
;
1747 BOOLEAN IsImageSection
;
1749 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1751 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1752 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1755 * Get the segment and section.
1757 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1758 Section
= MemoryArea
->Data
.SectionData
.Section
;
1759 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1761 FileObject
= Section
->FileObject
;
1762 DirectMapped
= FALSE
;
1763 if (FileObject
!= NULL
&&
1764 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1766 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1769 * If the file system is letting us go directly to the cache and the
1770 * memory area was mapped at an offset in the file which is page aligned
1771 * then note this is a direct mapped page.
1773 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1774 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1776 DirectMapped
= TRUE
;
1781 * This should never happen since mappings of physical memory are never
1782 * placed in the rmap lists.
1784 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1786 DPRINT1("Trying to write back page from physical memory mapped at %X "
1787 "process %d\n", Address
,
1788 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1793 * Get the section segment entry and the physical address.
1795 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1796 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1798 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1799 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1802 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1803 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1806 * Check for a private (COWed) page.
1808 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1809 IS_SWAP_FROM_SSE(Entry
) ||
1810 PFN_FROM_SSE(Entry
) != Page
)
1820 * Speculatively set all mappings of the page to clean.
1822 MmSetCleanAllRmaps(Page
);
1825 * If this page was direct mapped from the cache then the cache manager
1826 * will take care of writing it back to disk.
1828 if (DirectMapped
&& !Private
)
1830 ASSERT(SwapEntry
== 0);
1831 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1832 PageOp
->Status
= STATUS_SUCCESS
;
1833 MmspCompleteAndReleasePageOp(PageOp
);
1834 return(STATUS_SUCCESS
);
1838 * If necessary, allocate an entry in the paging file for this page
1842 SwapEntry
= MmAllocSwapPage();
1845 MmSetDirtyAllRmaps(Page
);
1846 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1847 MmspCompleteAndReleasePageOp(PageOp
);
1848 return(STATUS_PAGEFILE_QUOTA
);
1850 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1854 * Write the page to the pagefile
1856 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1857 if (!NT_SUCCESS(Status
))
1859 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1861 MmSetDirtyAllRmaps(Page
);
1862 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1863 MmspCompleteAndReleasePageOp(PageOp
);
1864 return(STATUS_UNSUCCESSFUL
);
1868 * Otherwise we have succeeded.
1870 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1871 PageOp
->Status
= STATUS_SUCCESS
;
1872 MmspCompleteAndReleasePageOp(PageOp
);
1873 return(STATUS_SUCCESS
);
1877 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1885 PMEMORY_AREA MemoryArea
;
1886 PMM_SECTION_SEGMENT Segment
;
1890 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1891 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1893 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1894 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1899 if (OldProtect
!= NewProtect
)
1901 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1903 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1904 ULONG Protect
= NewProtect
;
1907 * If we doing COW for this segment then check if the page is
1910 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1916 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1917 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1918 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1919 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1921 Protect
= PAGE_READONLY
;
1922 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1923 IS_SWAP_FROM_SSE(Entry
) ||
1924 PFN_FROM_SSE(Entry
) != Page
)
1926 Protect
= NewProtect
;
1930 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1932 MmSetPageProtect(AddressSpace
->Process
, Address
,
1941 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1942 PMEMORY_AREA MemoryArea
,
1950 ULONG_PTR MaxLength
;
1952 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1953 if (Length
> MaxLength
)
1956 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1957 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1959 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
1960 Region
->Protect
!= Protect
)
1963 return STATUS_INVALID_PAGE_PROTECTION
;
1966 *OldProtect
= Region
->Protect
;
1967 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1968 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1969 BaseAddress
, Length
, Region
->Type
, Protect
,
1970 MmAlterViewAttributes
);
1976 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1978 PMEMORY_BASIC_INFORMATION Info
,
1979 PULONG ResultLength
)
1982 PVOID RegionBaseAddress
;
1983 PSECTION_OBJECT Section
;
1984 PMM_SECTION_SEGMENT Segment
;
1986 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1987 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1988 Address
, &RegionBaseAddress
);
1991 return STATUS_UNSUCCESSFUL
;
1994 Section
= MemoryArea
->Data
.SectionData
.Section
;
1995 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1997 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1998 Info
->AllocationBase
= (PBYTE
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
1999 Info
->Type
= MEM_IMAGE
;
2003 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2004 Info
->Type
= MEM_MAPPED
;
2006 Info
->BaseAddress
= RegionBaseAddress
;
2007 Info
->AllocationProtect
= MemoryArea
->Protect
;
2008 Info
->RegionSize
= Region
->Length
;
2009 Info
->State
= MEM_COMMIT
;
2010 Info
->Protect
= Region
->Protect
;
2012 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2013 return(STATUS_SUCCESS
);
2018 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2023 ULONG SavedSwapEntry
;
2028 Length
= PAGE_ROUND_UP(Segment
->Length
);
2029 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2031 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2034 if (IS_SWAP_FROM_SSE(Entry
))
2036 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2040 Page
= PFN_FROM_SSE(Entry
);
2041 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2042 if (SavedSwapEntry
!= 0)
2044 MmSetSavedSwapEntryPage(Page
, 0);
2045 MmFreeSwapPage(SavedSwapEntry
);
2047 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2049 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2055 MmpDeleteSection(PVOID ObjectBody
)
2057 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2059 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2060 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2065 PMM_SECTION_SEGMENT SectionSegments
;
2068 * NOTE: Section->ImageSection can be NULL for short time
2069 * during the section creating. If we fail for some reason
2070 * until the image section is properly initialized we shouldn't
2071 * process further here.
2073 if (Section
->ImageSection
== NULL
)
2076 SectionSegments
= Section
->ImageSection
->Segments
;
2077 NrSegments
= Section
->ImageSection
->NrSegments
;
2079 for (i
= 0; i
< NrSegments
; i
++)
2081 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2083 MmLockSectionSegment(&SectionSegments
[i
]);
2085 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2086 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2090 MmpFreePageFileSegment(&SectionSegments
[i
]);
2092 MmUnlockSectionSegment(&SectionSegments
[i
]);
2099 * NOTE: Section->Segment can be NULL for short time
2100 * during the section creating.
2102 if (Section
->Segment
== NULL
)
2105 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2107 MmpFreePageFileSegment(Section
->Segment
);
2108 MmFreePageTablesSectionSegment(Section
->Segment
);
2109 ExFreePool(Section
->Segment
);
2110 Section
->Segment
= NULL
;
2114 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2117 if (Section
->FileObject
!= NULL
)
2119 CcRosDereferenceCache(Section
->FileObject
);
2120 ObDereferenceObject(Section
->FileObject
);
2121 Section
->FileObject
= NULL
;
2126 MmpCloseSection(PVOID ObjectBody
,
2129 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2130 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2136 MmCreatePhysicalMemorySection(VOID
)
2138 PSECTION_OBJECT PhysSection
;
2140 OBJECT_ATTRIBUTES Obj
;
2141 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2142 LARGE_INTEGER SectionSize
;
2145 * Create the section mapping physical memory
2147 SectionSize
.QuadPart
= 0xFFFFFFFF;
2148 InitializeObjectAttributes(&Obj
,
2153 Status
= MmCreateSection((PVOID
)&PhysSection
,
2157 PAGE_EXECUTE_READWRITE
,
2161 if (!NT_SUCCESS(Status
))
2163 DbgPrint("Failed to create PhysicalMemory section\n");
2166 Status
= ObInsertObject(PhysSection
,
2172 if (!NT_SUCCESS(Status
))
2174 ObDereferenceObject(PhysSection
);
2176 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2177 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2179 return(STATUS_SUCCESS
);
2185 MmInitSectionImplementation(VOID
)
2187 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2188 UNICODE_STRING Name
;
2190 DPRINT("Creating Section Object Type\n");
2192 /* Initialize the Section object type */
2193 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2194 RtlInitUnicodeString(&Name
, L
"Section");
2195 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2196 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(SECTION_OBJECT
);
2197 ObjectTypeInitializer
.PoolType
= PagedPool
;
2198 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2199 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2200 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2201 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2202 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &MmSectionObjectType
);
2204 return(STATUS_SUCCESS
);
2209 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2210 ACCESS_MASK DesiredAccess
,
2211 POBJECT_ATTRIBUTES ObjectAttributes
,
2212 PLARGE_INTEGER UMaximumSize
,
2213 ULONG SectionPageProtection
,
2214 ULONG AllocationAttributes
)
2216 * Create a section which is backed by the pagefile
2219 LARGE_INTEGER MaximumSize
;
2220 PSECTION_OBJECT Section
;
2221 PMM_SECTION_SEGMENT Segment
;
2224 if (UMaximumSize
== NULL
)
2226 return(STATUS_UNSUCCESSFUL
);
2228 MaximumSize
= *UMaximumSize
;
2231 * Create the section
2233 Status
= ObCreateObject(ExGetPreviousMode(),
2234 MmSectionObjectType
,
2236 ExGetPreviousMode(),
2238 sizeof(SECTION_OBJECT
),
2241 (PVOID
*)(PVOID
)&Section
);
2242 if (!NT_SUCCESS(Status
))
2250 Section
->SectionPageProtection
= SectionPageProtection
;
2251 Section
->AllocationAttributes
= AllocationAttributes
;
2252 Section
->Segment
= NULL
;
2253 Section
->FileObject
= NULL
;
2254 Section
->MaximumSize
= MaximumSize
;
2255 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2256 TAG_MM_SECTION_SEGMENT
);
2257 if (Segment
== NULL
)
2259 ObDereferenceObject(Section
);
2260 return(STATUS_NO_MEMORY
);
2262 Section
->Segment
= Segment
;
2263 Segment
->ReferenceCount
= 1;
2264 ExInitializeFastMutex(&Segment
->Lock
);
2265 Segment
->FileOffset
= 0;
2266 Segment
->Protection
= SectionPageProtection
;
2267 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2268 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2269 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2270 Segment
->WriteCopy
= FALSE
;
2271 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2272 Segment
->VirtualAddress
= 0;
2273 Segment
->Characteristics
= 0;
2274 *SectionObject
= Section
;
2275 return(STATUS_SUCCESS
);
2281 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2282 ACCESS_MASK DesiredAccess
,
2283 POBJECT_ATTRIBUTES ObjectAttributes
,
2284 PLARGE_INTEGER UMaximumSize
,
2285 ULONG SectionPageProtection
,
2286 ULONG AllocationAttributes
,
2289 * Create a section backed by a data file
2292 PSECTION_OBJECT Section
;
2294 LARGE_INTEGER MaximumSize
;
2295 PFILE_OBJECT FileObject
;
2296 PMM_SECTION_SEGMENT Segment
;
2298 IO_STATUS_BLOCK Iosb
;
2299 LARGE_INTEGER Offset
;
2301 FILE_STANDARD_INFORMATION FileInfo
;
2304 * Create the section
2306 Status
= ObCreateObject(ExGetPreviousMode(),
2307 MmSectionObjectType
,
2309 ExGetPreviousMode(),
2311 sizeof(SECTION_OBJECT
),
2314 (PVOID
*)(PVOID
)&Section
);
2315 if (!NT_SUCCESS(Status
))
2322 Section
->SectionPageProtection
= SectionPageProtection
;
2323 Section
->AllocationAttributes
= AllocationAttributes
;
2324 Section
->Segment
= NULL
;
2327 * Check file access required
2329 if (SectionPageProtection
& PAGE_READWRITE
||
2330 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2332 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2336 FileAccess
= FILE_READ_DATA
;
2340 * Reference the file handle
2342 Status
= ObReferenceObjectByHandle(FileHandle
,
2346 (PVOID
*)(PVOID
)&FileObject
,
2348 if (!NT_SUCCESS(Status
))
2350 ObDereferenceObject(Section
);
2355 * FIXME: This is propably not entirely correct. We can't look into
2356 * the standard FCB header because it might not be initialized yet
2357 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2358 * standard file information is filled on first request).
2360 Status
= IoQueryFileInformation(FileObject
,
2361 FileStandardInformation
,
2362 sizeof(FILE_STANDARD_INFORMATION
),
2365 if (!NT_SUCCESS(Status
))
2367 ObDereferenceObject(Section
);
2368 ObDereferenceObject(FileObject
);
2373 * FIXME: Revise this once a locking order for file size changes is
2376 if (UMaximumSize
!= NULL
)
2378 MaximumSize
= *UMaximumSize
;
2382 MaximumSize
= FileInfo
.EndOfFile
;
2383 /* Mapping zero-sized files isn't allowed. */
2384 if (MaximumSize
.QuadPart
== 0)
2386 ObDereferenceObject(Section
);
2387 ObDereferenceObject(FileObject
);
2388 return STATUS_FILE_INVALID
;
2392 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2394 Status
= IoSetInformation(FileObject
,
2395 FileAllocationInformation
,
2396 sizeof(LARGE_INTEGER
),
2398 if (!NT_SUCCESS(Status
))
2400 ObDereferenceObject(Section
);
2401 ObDereferenceObject(FileObject
);
2402 return(STATUS_SECTION_NOT_EXTENDED
);
2406 if (FileObject
->SectionObjectPointer
== NULL
||
2407 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2410 * Read a bit so caching is initiated for the file object.
2411 * This is only needed because MiReadPage currently cannot
2412 * handle non-cached streams.
2414 Offset
.QuadPart
= 0;
2415 Status
= ZwReadFile(FileHandle
,
2424 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2426 ObDereferenceObject(Section
);
2427 ObDereferenceObject(FileObject
);
2430 if (FileObject
->SectionObjectPointer
== NULL
||
2431 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2433 /* FIXME: handle this situation */
2434 ObDereferenceObject(Section
);
2435 ObDereferenceObject(FileObject
);
2436 return STATUS_INVALID_PARAMETER
;
2443 Status
= MmspWaitForFileLock(FileObject
);
2444 if (Status
!= STATUS_SUCCESS
)
2446 ObDereferenceObject(Section
);
2447 ObDereferenceObject(FileObject
);
2452 * If this file hasn't been mapped as a data file before then allocate a
2453 * section segment to describe the data file mapping
2455 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2457 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2458 TAG_MM_SECTION_SEGMENT
);
2459 if (Segment
== NULL
)
2461 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2462 ObDereferenceObject(Section
);
2463 ObDereferenceObject(FileObject
);
2464 return(STATUS_NO_MEMORY
);
2466 Section
->Segment
= Segment
;
2467 Segment
->ReferenceCount
= 1;
2468 ExInitializeFastMutex(&Segment
->Lock
);
2470 * Set the lock before assigning the segment to the file object
2472 ExAcquireFastMutex(&Segment
->Lock
);
2473 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2475 Segment
->FileOffset
= 0;
2476 Segment
->Protection
= SectionPageProtection
;
2477 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2478 Segment
->Characteristics
= 0;
2479 Segment
->WriteCopy
= FALSE
;
2480 if (AllocationAttributes
& SEC_RESERVE
)
2482 Segment
->Length
= Segment
->RawLength
= 0;
2486 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2487 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2489 Segment
->VirtualAddress
= 0;
2490 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2495 * If the file is already mapped as a data file then we may need
2499 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2501 Section
->Segment
= Segment
;
2502 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2503 MmLockSectionSegment(Segment
);
2505 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2506 !(AllocationAttributes
& SEC_RESERVE
))
2508 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2509 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2512 MmUnlockSectionSegment(Segment
);
2513 Section
->FileObject
= FileObject
;
2514 Section
->MaximumSize
= MaximumSize
;
2515 CcRosReferenceCache(FileObject
);
2516 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2517 *SectionObject
= Section
;
2518 return(STATUS_SUCCESS
);
2522 TODO: not that great (declaring loaders statically, having to declare all of
2523 them, having to keep them extern, etc.), will fix in the future
2525 extern NTSTATUS NTAPI PeFmtCreateSection
2527 IN CONST VOID
* FileHeader
,
2528 IN SIZE_T FileHeaderSize
,
2530 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2532 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2533 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2536 extern NTSTATUS NTAPI ElfFmtCreateSection
2538 IN CONST VOID
* FileHeader
,
2539 IN SIZE_T FileHeaderSize
,
2541 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2543 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2544 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2547 /* TODO: this is a standard DDK/PSDK macro */
2548 #ifndef RTL_NUMBER_OF
2549 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2552 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2561 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2563 SIZE_T SizeOfSegments
;
2564 PMM_SECTION_SEGMENT Segments
;
2566 /* TODO: check for integer overflow */
2567 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2569 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2571 TAG_MM_SECTION_SEGMENT
);
2574 RtlZeroMemory(Segments
, SizeOfSegments
);
2582 ExeFmtpReadFile(IN PVOID File
,
2583 IN PLARGE_INTEGER Offset
,
2586 OUT PVOID
* AllocBase
,
2587 OUT PULONG ReadSize
)
2590 LARGE_INTEGER FileOffset
;
2592 ULONG OffsetAdjustment
;
2597 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2601 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2604 FileOffset
= *Offset
;
2606 /* Negative/special offset: it cannot be used in this context */
2607 if(FileOffset
.u
.HighPart
< 0)
2609 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2612 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2613 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2614 FileOffset
.u
.LowPart
= AdjustOffset
;
2616 BufferSize
= Length
+ OffsetAdjustment
;
2617 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2620 * It's ok to use paged pool, because this is a temporary buffer only used in
2621 * the loading of executables. The assumption is that MmCreateSection is
2622 * always called at low IRQLs and that these buffers don't survive a brief
2623 * initialization phase
2625 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2627 TAG('M', 'm', 'X', 'r'));
2632 Status
= MmspPageRead(File
,
2639 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2640 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2641 * to initialize internal state is even worse. Our cache manager is in need of
2645 IO_STATUS_BLOCK Iosb
;
2647 Status
= ZwReadFile(File
,
2657 if(NT_SUCCESS(Status
))
2659 UsedSize
= Iosb
.Information
;
2664 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2666 Status
= STATUS_IN_PAGE_ERROR
;
2667 ASSERT(!NT_SUCCESS(Status
));
2670 if(NT_SUCCESS(Status
))
2672 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2673 *AllocBase
= Buffer
;
2674 *ReadSize
= UsedSize
- OffsetAdjustment
;
2685 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2686 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2687 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2692 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2696 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2698 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2699 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2706 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2710 MmspAssertSegmentsSorted(ImageSectionObject
);
2712 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2714 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2718 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2719 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2720 ImageSectionObject
->Segments
[i
- 1].Length
));
2728 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2732 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2734 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2735 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2743 MmspCompareSegments(const void * x
,
2746 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2747 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2750 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2751 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2755 * Ensures an image section's segments are sorted in memory
2760 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2763 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2765 MmspAssertSegmentsSorted(ImageSectionObject
);
2769 qsort(ImageSectionObject
->Segments
,
2770 ImageSectionObject
->NrSegments
,
2771 sizeof(ImageSectionObject
->Segments
[0]),
2772 MmspCompareSegments
);
2778 * Ensures an image section's segments don't overlap in memory and don't have
2779 * gaps and don't have a null size. We let them map to overlapping file regions,
2780 * though - that's not necessarily an error
2785 MmspCheckSegmentBounds
2787 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2793 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2795 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2799 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2801 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2803 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2811 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2812 * page could be OK (Windows seems to be OK with them), and larger gaps
2813 * could lead to image sections spanning several discontiguous regions
2814 * (NtMapViewOfSection could then refuse to map them, and they could
2815 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2817 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2818 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2819 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2830 * Merges and pads an image section's segments until they all are page-aligned
2831 * and have a size that is a multiple of the page size
2836 MmspPageAlignSegments
2838 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2844 BOOLEAN Initialized
;
2845 PMM_SECTION_SEGMENT EffectiveSegment
;
2847 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2849 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2853 Initialized
= FALSE
;
2855 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2857 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2860 * The first segment requires special handling
2864 ULONG_PTR VirtualAddress
;
2865 ULONG_PTR VirtualOffset
;
2867 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2869 /* Round down the virtual address to the nearest page */
2870 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2872 /* Round up the virtual size to the nearest page */
2873 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2874 EffectiveSegment
->VirtualAddress
;
2876 /* Adjust the raw address and size */
2877 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2879 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2885 * Garbage in, garbage out: unaligned base addresses make the file
2886 * offset point in curious and odd places, but that's what we were
2889 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2890 EffectiveSegment
->RawLength
+= VirtualOffset
;
2894 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2895 ULONG_PTR EndOfEffectiveSegment
;
2897 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2898 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2901 * The current segment begins exactly where the current effective
2902 * segment ended, therefore beginning a new effective segment
2904 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2907 ASSERT(LastSegment
<= i
);
2908 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2910 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2912 if (LastSegment
!= i
)
2915 * Copy the current segment. If necessary, the effective segment
2916 * will be expanded later
2918 *EffectiveSegment
= *Segment
;
2922 * Page-align the virtual size. We know for sure the virtual address
2925 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2926 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2929 * The current segment is still part of the current effective segment:
2930 * extend the effective segment to reflect this
2932 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2934 static const ULONG FlagsToProtection
[16] =
2942 PAGE_EXECUTE_READWRITE
,
2943 PAGE_EXECUTE_READWRITE
,
2948 PAGE_EXECUTE_WRITECOPY
,
2949 PAGE_EXECUTE_WRITECOPY
,
2950 PAGE_EXECUTE_WRITECOPY
,
2951 PAGE_EXECUTE_WRITECOPY
2954 unsigned ProtectionFlags
;
2957 * Extend the file size
2960 /* Unaligned segments must be contiguous within the file */
2961 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2962 EffectiveSegment
->RawLength
))
2967 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2970 * Extend the virtual size
2972 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
2974 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2975 EffectiveSegment
->VirtualAddress
;
2978 * Merge the protection
2980 EffectiveSegment
->Protection
|= Segment
->Protection
;
2982 /* Clean up redundance */
2983 ProtectionFlags
= 0;
2985 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2986 ProtectionFlags
|= 1 << 0;
2988 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2989 ProtectionFlags
|= 1 << 1;
2991 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2992 ProtectionFlags
|= 1 << 2;
2994 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2995 ProtectionFlags
|= 1 << 3;
2997 ASSERT(ProtectionFlags
< 16);
2998 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3000 /* If a segment was required to be shared and cannot, fail */
3001 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3002 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3008 * We assume no holes between segments at this point
3016 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3022 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3023 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3025 LARGE_INTEGER Offset
;
3027 PVOID FileHeaderBuffer
;
3028 ULONG FileHeaderSize
;
3030 ULONG OldNrSegments
;
3035 * Read the beginning of the file (2 pages). Should be enough to contain
3036 * all (or most) of the headers
3038 Offset
.QuadPart
= 0;
3040 /* FIXME: use FileObject instead of FileHandle */
3041 Status
= ExeFmtpReadFile (FileHandle
,
3048 if (!NT_SUCCESS(Status
))
3051 if (FileHeaderSize
== 0)
3053 ExFreePool(FileHeaderBuffer
);
3054 return STATUS_UNSUCCESSFUL
;
3058 * Look for a loader that can handle this executable
3060 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3062 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3065 /* FIXME: use FileObject instead of FileHandle */
3066 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3072 ExeFmtpAllocateSegments
);
3074 if (!NT_SUCCESS(Status
))
3076 if (ImageSectionObject
->Segments
)
3078 ExFreePool(ImageSectionObject
->Segments
);
3079 ImageSectionObject
->Segments
= NULL
;
3083 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3087 ExFreePool(FileHeaderBuffer
);
3090 * No loader handled the format
3092 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3094 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3095 ASSERT(!NT_SUCCESS(Status
));
3098 if (!NT_SUCCESS(Status
))
3101 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3106 /* FIXME? are these values platform-dependent? */
3107 if(ImageSectionObject
->StackReserve
== 0)
3108 ImageSectionObject
->StackReserve
= 0x40000;
3110 if(ImageSectionObject
->StackCommit
== 0)
3111 ImageSectionObject
->StackCommit
= 0x1000;
3113 if(ImageSectionObject
->ImageBase
== 0)
3115 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3116 ImageSectionObject
->ImageBase
= 0x10000000;
3118 ImageSectionObject
->ImageBase
= 0x00400000;
3122 * And now the fun part: fixing the segments
3125 /* Sort them by virtual address */
3126 MmspSortSegments(ImageSectionObject
, Flags
);
3128 /* Ensure they don't overlap in memory */
3129 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3130 return STATUS_INVALID_IMAGE_FORMAT
;
3132 /* Ensure they are aligned */
3133 OldNrSegments
= ImageSectionObject
->NrSegments
;
3135 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3136 return STATUS_INVALID_IMAGE_FORMAT
;
3138 /* Trim them if the alignment phase merged some of them */
3139 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3141 PMM_SECTION_SEGMENT Segments
;
3142 SIZE_T SizeOfSegments
;
3144 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3146 Segments
= ExAllocatePoolWithTag(PagedPool
,
3148 TAG_MM_SECTION_SEGMENT
);
3150 if (Segments
== NULL
)
3151 return STATUS_INSUFFICIENT_RESOURCES
;
3153 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3154 ExFreePool(ImageSectionObject
->Segments
);
3155 ImageSectionObject
->Segments
= Segments
;
3158 /* And finish their initialization */
3159 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3161 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3162 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3164 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3165 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3168 ASSERT(NT_SUCCESS(Status
));
3173 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3174 ACCESS_MASK DesiredAccess
,
3175 POBJECT_ATTRIBUTES ObjectAttributes
,
3176 PLARGE_INTEGER UMaximumSize
,
3177 ULONG SectionPageProtection
,
3178 ULONG AllocationAttributes
,
3181 PSECTION_OBJECT Section
;
3183 PFILE_OBJECT FileObject
;
3184 PMM_SECTION_SEGMENT SectionSegments
;
3185 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3187 ULONG FileAccess
= 0;
3190 * Specifying a maximum size is meaningless for an image section
3192 if (UMaximumSize
!= NULL
)
3194 return(STATUS_INVALID_PARAMETER_4
);
3198 * Check file access required
3200 if (SectionPageProtection
& PAGE_READWRITE
||
3201 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3203 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3207 FileAccess
= FILE_READ_DATA
;
3211 * Reference the file handle
3213 Status
= ObReferenceObjectByHandle(FileHandle
,
3217 (PVOID
*)(PVOID
)&FileObject
,
3220 if (!NT_SUCCESS(Status
))
3226 * Create the section
3228 Status
= ObCreateObject (ExGetPreviousMode(),
3229 MmSectionObjectType
,
3231 ExGetPreviousMode(),
3233 sizeof(SECTION_OBJECT
),
3236 (PVOID
*)(PVOID
)&Section
);
3237 if (!NT_SUCCESS(Status
))
3239 ObDereferenceObject(FileObject
);
3246 Section
->SectionPageProtection
= SectionPageProtection
;
3247 Section
->AllocationAttributes
= AllocationAttributes
;
3250 * Initialized caching for this file object if previously caching
3251 * was initialized for the same on disk file
3253 Status
= CcTryToInitializeFileCache(FileObject
);
3255 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3257 NTSTATUS StatusExeFmt
;
3259 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3260 if (ImageSectionObject
== NULL
)
3262 ObDereferenceObject(FileObject
);
3263 ObDereferenceObject(Section
);
3264 return(STATUS_NO_MEMORY
);
3267 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3269 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3271 if (!NT_SUCCESS(StatusExeFmt
))
3273 if(ImageSectionObject
->Segments
!= NULL
)
3274 ExFreePool(ImageSectionObject
->Segments
);
3276 ExFreePool(ImageSectionObject
);
3277 ObDereferenceObject(Section
);
3278 ObDereferenceObject(FileObject
);
3279 return(StatusExeFmt
);
3282 Section
->ImageSection
= ImageSectionObject
;
3283 ASSERT(ImageSectionObject
->Segments
);
3288 Status
= MmspWaitForFileLock(FileObject
);
3289 if (!NT_SUCCESS(Status
))
3291 ExFreePool(ImageSectionObject
->Segments
);
3292 ExFreePool(ImageSectionObject
);
3293 ObDereferenceObject(Section
);
3294 ObDereferenceObject(FileObject
);
3298 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3299 ImageSectionObject
, NULL
))
3302 * An other thread has initialized the some image in the background
3304 ExFreePool(ImageSectionObject
->Segments
);
3305 ExFreePool(ImageSectionObject
);
3306 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3307 Section
->ImageSection
= ImageSectionObject
;
3308 SectionSegments
= ImageSectionObject
->Segments
;
3310 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3312 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3316 Status
= StatusExeFmt
;
3323 Status
= MmspWaitForFileLock(FileObject
);
3324 if (Status
!= STATUS_SUCCESS
)
3326 ObDereferenceObject(Section
);
3327 ObDereferenceObject(FileObject
);
3331 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3332 Section
->ImageSection
= ImageSectionObject
;
3333 SectionSegments
= ImageSectionObject
->Segments
;
3336 * Otherwise just reference all the section segments
3338 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3340 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3343 Status
= STATUS_SUCCESS
;
3345 Section
->FileObject
= FileObject
;
3346 CcRosReferenceCache(FileObject
);
3347 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3348 *SectionObject
= Section
;
3356 NtCreateSection (OUT PHANDLE SectionHandle
,
3357 IN ACCESS_MASK DesiredAccess
,
3358 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3359 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3360 IN ULONG SectionPageProtection OPTIONAL
,
3361 IN ULONG AllocationAttributes
,
3362 IN HANDLE FileHandle OPTIONAL
)
3364 LARGE_INTEGER SafeMaximumSize
;
3365 PVOID SectionObject
;
3366 KPROCESSOR_MODE PreviousMode
;
3367 NTSTATUS Status
= STATUS_SUCCESS
;
3369 PreviousMode
= ExGetPreviousMode();
3371 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3375 /* make a copy on the stack */
3376 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3377 MaximumSize
= &SafeMaximumSize
;
3381 Status
= _SEH_GetExceptionCode();
3385 if(!NT_SUCCESS(Status
))
3391 Status
= MmCreateSection(&SectionObject
,
3395 SectionPageProtection
,
3396 AllocationAttributes
,
3400 if (NT_SUCCESS(Status
))
3402 Status
= ObInsertObject ((PVOID
)SectionObject
,
3408 ObDereferenceObject(SectionObject
);
3415 /**********************************************************************
3433 NtOpenSection(PHANDLE SectionHandle
,
3434 ACCESS_MASK DesiredAccess
,
3435 POBJECT_ATTRIBUTES ObjectAttributes
)
3438 KPROCESSOR_MODE PreviousMode
;
3439 NTSTATUS Status
= STATUS_SUCCESS
;
3441 PreviousMode
= ExGetPreviousMode();
3443 if(PreviousMode
!= KernelMode
)
3447 ProbeForWriteHandle(SectionHandle
);
3451 Status
= _SEH_GetExceptionCode();
3455 if(!NT_SUCCESS(Status
))
3461 Status
= ObOpenObjectByName(ObjectAttributes
,
3462 MmSectionObjectType
,
3469 if(NT_SUCCESS(Status
))
3473 *SectionHandle
= hSection
;
3477 Status
= _SEH_GetExceptionCode();
3486 MmMapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3487 PSECTION_OBJECT Section
,
3488 PMM_SECTION_SEGMENT Segment
,
3493 ULONG AllocationType
)
3497 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3499 BoundaryAddressMultiple
.QuadPart
= 0;
3501 Status
= MmCreateMemoryArea(AddressSpace
,
3502 MEMORY_AREA_SECTION_VIEW
,
3509 BoundaryAddressMultiple
);
3510 if (!NT_SUCCESS(Status
))
3512 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3513 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3517 ObReferenceObject((PVOID
)Section
);
3519 MArea
->Data
.SectionData
.Segment
= Segment
;
3520 MArea
->Data
.SectionData
.Section
= Section
;
3521 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3522 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3523 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3524 ViewSize
, 0, Protect
);
3526 return(STATUS_SUCCESS
);
3530 /**********************************************************************
3532 * NtMapViewOfSection
3535 * Maps a view of a section into the virtual address space of a
3540 * Handle of the section.
3543 * Handle of the process.
3546 * Desired base address (or NULL) on entry;
3547 * Actual base address of the view on exit.
3550 * Number of high order address bits that must be zero.
3553 * Size in bytes of the initially committed section of
3557 * Offset in bytes from the beginning of the section
3558 * to the beginning of the view.
3561 * Desired length of map (or zero to map all) on entry
3562 * Actual length mapped on exit.
3564 * InheritDisposition
3565 * Specified how the view is to be shared with
3569 * Type of allocation for the pages.
3572 * Protection for the committed region of the view.
3580 NtMapViewOfSection(IN HANDLE SectionHandle
,
3581 IN HANDLE ProcessHandle
,
3582 IN OUT PVOID
* BaseAddress OPTIONAL
,
3583 IN ULONG ZeroBits OPTIONAL
,
3584 IN ULONG CommitSize
,
3585 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3586 IN OUT PSIZE_T ViewSize
,
3587 IN SECTION_INHERIT InheritDisposition
,
3588 IN ULONG AllocationType OPTIONAL
,
3591 PVOID SafeBaseAddress
;
3592 LARGE_INTEGER SafeSectionOffset
;
3593 SIZE_T SafeViewSize
;
3594 PSECTION_OBJECT Section
;
3596 KPROCESSOR_MODE PreviousMode
;
3597 PMADDRESS_SPACE AddressSpace
;
3598 NTSTATUS Status
= STATUS_SUCCESS
;
3602 * Check the protection
3604 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3607 return STATUS_INVALID_PARAMETER_10
;
3610 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3611 if (tmpProtect
!= PAGE_NOACCESS
&&
3612 tmpProtect
!= PAGE_READONLY
&&
3613 tmpProtect
!= PAGE_READWRITE
&&
3614 tmpProtect
!= PAGE_WRITECOPY
&&
3615 tmpProtect
!= PAGE_EXECUTE
&&
3616 tmpProtect
!= PAGE_EXECUTE_READ
&&
3617 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3618 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3621 return STATUS_INVALID_PAGE_PROTECTION
;
3624 PreviousMode
= ExGetPreviousMode();
3626 if(PreviousMode
!= KernelMode
)
3628 SafeBaseAddress
= NULL
;
3629 SafeSectionOffset
.QuadPart
= 0;
3634 if(BaseAddress
!= NULL
)
3636 ProbeForWritePointer(BaseAddress
);
3637 SafeBaseAddress
= *BaseAddress
;
3639 if(SectionOffset
!= NULL
)
3641 ProbeForWriteLargeInteger(SectionOffset
);
3642 SafeSectionOffset
= *SectionOffset
;
3644 ProbeForWriteSize_t(ViewSize
);
3645 SafeViewSize
= *ViewSize
;
3649 Status
= _SEH_GetExceptionCode();
3653 if(!NT_SUCCESS(Status
))
3660 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3661 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3662 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3665 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3666 PROCESS_VM_OPERATION
,
3669 (PVOID
*)(PVOID
)&Process
,
3671 if (!NT_SUCCESS(Status
))
3676 AddressSpace
= &Process
->AddressSpace
;
3678 Status
= ObReferenceObjectByHandle(SectionHandle
,
3680 MmSectionObjectType
,
3682 (PVOID
*)(PVOID
)&Section
,
3684 if (!(NT_SUCCESS(Status
)))
3686 DPRINT("ObReference failed rc=%x\n",Status
);
3687 ObDereferenceObject(Process
);
3691 Status
= MmMapViewOfSection(Section
,
3693 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3696 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3697 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3702 ObDereferenceObject(Section
);
3703 ObDereferenceObject(Process
);
3705 if(NT_SUCCESS(Status
))
3707 /* copy parameters back to the caller */
3710 if(BaseAddress
!= NULL
)
3712 *BaseAddress
= SafeBaseAddress
;
3714 if(SectionOffset
!= NULL
)
3716 *SectionOffset
= SafeSectionOffset
;
3718 if(ViewSize
!= NULL
)
3720 *ViewSize
= SafeViewSize
;
3725 Status
= _SEH_GetExceptionCode();
3734 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3735 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3738 PFILE_OBJECT FileObject
;
3741 SWAPENTRY SavedSwapEntry
;
3744 PSECTION_OBJECT Section
;
3745 PMM_SECTION_SEGMENT Segment
;
3746 PMADDRESS_SPACE AddressSpace
;
3748 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3750 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3752 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3753 MemoryArea
->Data
.SectionData
.ViewOffset
;
3755 Section
= MemoryArea
->Data
.SectionData
.Section
;
3756 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3758 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3762 MmUnlockSectionSegment(Segment
);
3763 MmUnlockAddressSpace(AddressSpace
);
3765 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3766 if (Status
!= STATUS_SUCCESS
)
3768 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3772 MmLockAddressSpace(AddressSpace
);
3773 MmLockSectionSegment(Segment
);
3774 MmspCompleteAndReleasePageOp(PageOp
);
3775 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3778 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3781 * For a dirty, datafile, non-private page mark it as dirty in the
3784 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3786 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3788 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3789 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3790 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3791 ASSERT(SwapEntry
== 0);
3800 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3802 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3805 MmFreeSwapPage(SwapEntry
);
3809 if (IS_SWAP_FROM_SSE(Entry
) ||
3810 Page
!= PFN_FROM_SSE(Entry
))
3815 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3817 DPRINT1("Found a private page in a pagefile section.\n");
3821 * Just dereference private pages
3823 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3824 if (SavedSwapEntry
!= 0)
3826 MmFreeSwapPage(SavedSwapEntry
);
3827 MmSetSavedSwapEntryPage(Page
, 0);
3829 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3830 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3834 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3835 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3841 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3845 PMEMORY_AREA MemoryArea
;
3846 PSECTION_OBJECT Section
;
3847 PMM_SECTION_SEGMENT Segment
;
3848 PLIST_ENTRY CurrentEntry
;
3849 PMM_REGION CurrentRegion
;
3850 PLIST_ENTRY RegionListHead
;
3852 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3854 if (MemoryArea
== NULL
)
3856 return(STATUS_UNSUCCESSFUL
);
3859 MemoryArea
->DeleteInProgress
= TRUE
;
3860 Section
= MemoryArea
->Data
.SectionData
.Section
;
3861 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3863 MmLockSectionSegment(Segment
);
3865 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3866 while (!IsListEmpty(RegionListHead
))
3868 CurrentEntry
= RemoveHeadList(RegionListHead
);
3869 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3870 ExFreePool(CurrentRegion
);
3873 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3875 Status
= MmFreeMemoryArea(AddressSpace
,
3882 Status
= MmFreeMemoryArea(AddressSpace
,
3887 MmUnlockSectionSegment(Segment
);
3888 ObDereferenceObject(Section
);
3889 return(STATUS_SUCCESS
);
3896 MmUnmapViewOfSection(PEPROCESS Process
,
3900 PMEMORY_AREA MemoryArea
;
3901 PMADDRESS_SPACE AddressSpace
;
3902 PSECTION_OBJECT Section
;
3906 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3907 Process
, BaseAddress
);
3911 AddressSpace
= &Process
->AddressSpace
;
3913 MmLockAddressSpace(AddressSpace
);
3914 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3916 if (MemoryArea
== NULL
||
3917 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3918 MemoryArea
->DeleteInProgress
)
3920 MmUnlockAddressSpace(AddressSpace
);
3921 return STATUS_NOT_MAPPED_VIEW
;
3924 MemoryArea
->DeleteInProgress
= TRUE
;
3926 while (MemoryArea
->PageOpCount
)
3928 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
3932 Offset
-= PAGE_SIZE
;
3933 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
3934 MemoryArea
->Data
.SectionData
.Segment
,
3935 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
3938 MmUnlockAddressSpace(AddressSpace
);
3939 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3940 if (Status
!= STATUS_SUCCESS
)
3942 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3945 MmLockAddressSpace(AddressSpace
);
3946 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3948 if (MemoryArea
== NULL
||
3949 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
3951 MmUnlockAddressSpace(AddressSpace
);
3952 return STATUS_NOT_MAPPED_VIEW
;
3959 Section
= MemoryArea
->Data
.SectionData
.Section
;
3961 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3965 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3966 PMM_SECTION_SEGMENT SectionSegments
;
3967 PVOID ImageBaseAddress
= 0;
3968 PMM_SECTION_SEGMENT Segment
;
3970 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3971 ImageSectionObject
= Section
->ImageSection
;
3972 SectionSegments
= ImageSectionObject
->Segments
;
3973 NrSegments
= ImageSectionObject
->NrSegments
;
3975 /* Search for the current segment within the section segments
3976 * and calculate the image base address */
3977 for (i
= 0; i
< NrSegments
; i
++)
3979 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3981 if (Segment
== &SectionSegments
[i
])
3983 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3988 if (i
>= NrSegments
)
3993 for (i
= 0; i
< NrSegments
; i
++)
3995 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3997 PVOID SBaseAddress
= (PVOID
)
3998 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4000 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4006 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4008 MmUnlockAddressSpace(AddressSpace
);
4009 return(STATUS_SUCCESS
);
4012 /**********************************************************************
4014 * NtUnmapViewOfSection
4029 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4033 KPROCESSOR_MODE PreviousMode
;
4036 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4037 ProcessHandle
, BaseAddress
);
4039 PreviousMode
= ExGetPreviousMode();
4041 DPRINT("Referencing process\n");
4042 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4043 PROCESS_VM_OPERATION
,
4046 (PVOID
*)(PVOID
)&Process
,
4048 if (!NT_SUCCESS(Status
))
4050 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4054 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4056 ObDereferenceObject(Process
);
4063 * Queries the information of a section object.
4065 * @param SectionHandle
4066 * Handle to the section object. It must be opened with SECTION_QUERY
4068 * @param SectionInformationClass
4069 * Index to a certain information structure. Can be either
4070 * SectionBasicInformation or SectionImageInformation. The latter
4071 * is valid only for sections that were created with the SEC_IMAGE
4073 * @param SectionInformation
4074 * Caller supplies storage for resulting information.
4076 * Size of the supplied storage.
4077 * @param ResultLength
4085 NtQuerySection(IN HANDLE SectionHandle
,
4086 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4087 OUT PVOID SectionInformation
,
4088 IN ULONG SectionInformationLength
,
4089 OUT PULONG ResultLength OPTIONAL
)
4091 PSECTION_OBJECT Section
;
4092 KPROCESSOR_MODE PreviousMode
;
4093 NTSTATUS Status
= STATUS_SUCCESS
;
4095 PreviousMode
= ExGetPreviousMode();
4097 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4099 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4101 SectionInformationLength
,
4105 if(!NT_SUCCESS(Status
))
4107 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4111 Status
= ObReferenceObjectByHandle(SectionHandle
,
4113 MmSectionObjectType
,
4115 (PVOID
*)(PVOID
)&Section
,
4117 if (NT_SUCCESS(Status
))
4119 switch (SectionInformationClass
)
4121 case SectionBasicInformation
:
4123 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4127 Sbi
->Attributes
= Section
->AllocationAttributes
;
4128 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4130 Sbi
->BaseAddress
= 0;
4131 Sbi
->Size
.QuadPart
= 0;
4135 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4136 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4139 if (ResultLength
!= NULL
)
4141 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4143 Status
= STATUS_SUCCESS
;
4147 Status
= _SEH_GetExceptionCode();
4154 case SectionImageInformation
:
4156 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4160 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4161 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4163 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4164 ImageSectionObject
= Section
->ImageSection
;
4166 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4167 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4168 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4169 Sii
->SubsystemType
= ImageSectionObject
->Subsystem
;
4170 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4171 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4172 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4173 Sii
->Machine
= ImageSectionObject
->Machine
;
4174 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4177 if (ResultLength
!= NULL
)
4179 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4181 Status
= STATUS_SUCCESS
;
4185 Status
= _SEH_GetExceptionCode();
4193 ObDereferenceObject(Section
);
4201 * Extends size of file backed section.
4203 * @param SectionHandle
4204 * Handle to the section object. It must be opened with
4205 * SECTION_EXTEND_SIZE access.
4206 * @param NewMaximumSize
4207 * New maximum size of the section in bytes.
4211 * @todo Move the actual code to internal function MmExtendSection.
4215 NtExtendSection(IN HANDLE SectionHandle
,
4216 IN PLARGE_INTEGER NewMaximumSize
)
4218 LARGE_INTEGER SafeNewMaximumSize
;
4219 PSECTION_OBJECT Section
;
4220 KPROCESSOR_MODE PreviousMode
;
4221 NTSTATUS Status
= STATUS_SUCCESS
;
4223 PreviousMode
= ExGetPreviousMode();
4225 if(PreviousMode
!= KernelMode
)
4229 /* make a copy on the stack */
4230 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4231 NewMaximumSize
= &SafeNewMaximumSize
;
4235 Status
= _SEH_GetExceptionCode();
4239 if(!NT_SUCCESS(Status
))
4245 Status
= ObReferenceObjectByHandle(SectionHandle
,
4246 SECTION_EXTEND_SIZE
,
4247 MmSectionObjectType
,
4251 if (!NT_SUCCESS(Status
))
4256 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4258 ObfDereferenceObject(Section
);
4259 return STATUS_INVALID_PARAMETER
;
4263 * - Acquire file extneding resource.
4264 * - Check if we're not resizing the section below it's actual size!
4265 * - Extend segments if needed.
4266 * - Set file information (FileAllocationInformation) to the new size.
4267 * - Release file extending resource.
4270 ObDereferenceObject(Section
);
4272 return STATUS_NOT_IMPLEMENTED
;
4276 /**********************************************************************
4278 * MmAllocateSection@4
4288 * Code taken from ntoskrnl/mm/special.c.
4293 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4299 PMADDRESS_SPACE AddressSpace
;
4300 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4302 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4304 BoundaryAddressMultiple
.QuadPart
= 0;
4306 AddressSpace
= MmGetKernelAddressSpace();
4307 Result
= BaseAddress
;
4308 MmLockAddressSpace(AddressSpace
);
4309 Status
= MmCreateMemoryArea (AddressSpace
,
4317 BoundaryAddressMultiple
);
4318 MmUnlockAddressSpace(AddressSpace
);
4320 if (!NT_SUCCESS(Status
))
4324 DPRINT("Result %p\n",Result
);
4325 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4329 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4330 if (!NT_SUCCESS(Status
))
4332 DbgPrint("Unable to allocate page\n");
4335 Status
= MmCreateVirtualMapping (NULL
,
4336 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4340 if (!NT_SUCCESS(Status
))
4342 DbgPrint("Unable to create virtual mapping\n");
4346 return ((PVOID
)Result
);
4350 /**********************************************************************
4352 * MmMapViewOfSection
4355 * Maps a view of a section into the virtual address space of a
4360 * Pointer to the section object.
4363 * Pointer to the process.
4366 * Desired base address (or NULL) on entry;
4367 * Actual base address of the view on exit.
4370 * Number of high order address bits that must be zero.
4373 * Size in bytes of the initially committed section of
4377 * Offset in bytes from the beginning of the section
4378 * to the beginning of the view.
4381 * Desired length of map (or zero to map all) on entry
4382 * Actual length mapped on exit.
4384 * InheritDisposition
4385 * Specified how the view is to be shared with
4389 * Type of allocation for the pages.
4392 * Protection for the committed region of the view.
4400 MmMapViewOfSection(IN PVOID SectionObject
,
4401 IN PEPROCESS Process
,
4402 IN OUT PVOID
*BaseAddress
,
4404 IN ULONG CommitSize
,
4405 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4406 IN OUT PSIZE_T ViewSize
,
4407 IN SECTION_INHERIT InheritDisposition
,
4408 IN ULONG AllocationType
,
4411 PSECTION_OBJECT Section
;
4412 PMADDRESS_SPACE AddressSpace
;
4414 NTSTATUS Status
= STATUS_SUCCESS
;
4418 if (Protect
!= PAGE_READONLY
&&
4419 Protect
!= PAGE_READWRITE
&&
4420 Protect
!= PAGE_WRITECOPY
&&
4421 Protect
!= PAGE_EXECUTE
&&
4422 Protect
!= PAGE_EXECUTE_READ
&&
4423 Protect
!= PAGE_EXECUTE_READWRITE
&&
4424 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4427 return STATUS_INVALID_PAGE_PROTECTION
;
4431 Section
= (PSECTION_OBJECT
)SectionObject
;
4432 AddressSpace
= &Process
->AddressSpace
;
4434 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4436 MmLockAddressSpace(AddressSpace
);
4438 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4442 ULONG_PTR ImageBase
;
4444 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4445 PMM_SECTION_SEGMENT SectionSegments
;
4447 ImageSectionObject
= Section
->ImageSection
;
4448 SectionSegments
= ImageSectionObject
->Segments
;
4449 NrSegments
= ImageSectionObject
->NrSegments
;
4452 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4455 ImageBase
= ImageSectionObject
->ImageBase
;
4459 for (i
= 0; i
< NrSegments
; i
++)
4461 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4463 ULONG_PTR MaxExtent
;
4464 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4465 SectionSegments
[i
].Length
;
4466 ImageSize
= max(ImageSize
, MaxExtent
);
4470 /* Check there is enough space to map the section at that point. */
4471 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4472 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4474 /* Fail if the user requested a fixed base address. */
4475 if ((*BaseAddress
) != NULL
)
4477 MmUnlockAddressSpace(AddressSpace
);
4478 return(STATUS_UNSUCCESSFUL
);
4480 /* Otherwise find a gap to map the image. */
4481 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4484 MmUnlockAddressSpace(AddressSpace
);
4485 return(STATUS_UNSUCCESSFUL
);
4489 for (i
= 0; i
< NrSegments
; i
++)
4491 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4493 PVOID SBaseAddress
= (PVOID
)
4494 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4495 MmLockSectionSegment(&SectionSegments
[i
]);
4496 Status
= MmMapViewOfSegment(AddressSpace
,
4498 &SectionSegments
[i
],
4500 SectionSegments
[i
].Length
,
4501 SectionSegments
[i
].Protection
,
4504 MmUnlockSectionSegment(&SectionSegments
[i
]);
4505 if (!NT_SUCCESS(Status
))
4507 MmUnlockAddressSpace(AddressSpace
);
4513 *BaseAddress
= (PVOID
)ImageBase
;
4517 /* check for write access */
4518 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4519 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4522 return STATUS_SECTION_PROTECTION
;
4524 /* check for read access */
4525 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4526 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4529 return STATUS_SECTION_PROTECTION
;
4531 /* check for execute access */
4532 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4533 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4536 return STATUS_SECTION_PROTECTION
;
4539 if (ViewSize
== NULL
)
4541 /* Following this pointer would lead to us to the dark side */
4542 /* What to do? Bugcheck? Return status? Do the mambo? */
4543 KEBUGCHECK(MEMORY_MANAGEMENT
);
4546 if (SectionOffset
== NULL
)
4552 ViewOffset
= SectionOffset
->u
.LowPart
;
4555 if ((ViewOffset
% PAGE_SIZE
) != 0)
4557 MmUnlockAddressSpace(AddressSpace
);
4558 return(STATUS_MAPPED_ALIGNMENT
);
4561 if ((*ViewSize
) == 0)
4563 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4565 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4567 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4570 MmLockSectionSegment(Section
->Segment
);
4571 Status
= MmMapViewOfSegment(AddressSpace
,
4578 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4579 MmUnlockSectionSegment(Section
->Segment
);
4580 if (!NT_SUCCESS(Status
))
4582 MmUnlockAddressSpace(AddressSpace
);
4587 MmUnlockAddressSpace(AddressSpace
);
4589 return(STATUS_SUCCESS
);
4596 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4597 IN PLARGE_INTEGER NewFileSize
)
4608 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4618 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4619 IN MMFLUSH_TYPE FlushType
)
4623 case MmFlushForDelete
:
4624 if (SectionObjectPointer
->ImageSectionObject
||
4625 SectionObjectPointer
->DataSectionObject
)
4629 CcRosSetRemoveOnClose(SectionObjectPointer
);
4631 case MmFlushForWrite
:
4641 MmForceSectionClosed (
4642 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4643 IN BOOLEAN DelayClose
)
4654 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4655 OUT PVOID
* MappedBase
,
4656 IN OUT PULONG ViewSize
)
4658 PSECTION_OBJECT Section
;
4659 PMADDRESS_SPACE AddressSpace
;
4662 DPRINT("MmMapViewInSystemSpace() called\n");
4664 Section
= (PSECTION_OBJECT
)SectionObject
;
4665 AddressSpace
= MmGetKernelAddressSpace();
4667 MmLockAddressSpace(AddressSpace
);
4670 if ((*ViewSize
) == 0)
4672 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4674 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4676 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4679 MmLockSectionSegment(Section
->Segment
);
4682 Status
= MmMapViewOfSegment(AddressSpace
,
4691 MmUnlockSectionSegment(Section
->Segment
);
4692 MmUnlockAddressSpace(AddressSpace
);
4702 MmMapViewInSessionSpace (
4704 OUT PVOID
*MappedBase
,
4705 IN OUT PSIZE_T ViewSize
4709 return STATUS_NOT_IMPLEMENTED
;
4717 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4719 PMADDRESS_SPACE AddressSpace
;
4722 DPRINT("MmUnmapViewInSystemSpace() called\n");
4724 AddressSpace
= MmGetKernelAddressSpace();
4726 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4736 MmUnmapViewInSessionSpace (
4741 return STATUS_NOT_IMPLEMENTED
;
4748 MmSetBankedSection (DWORD Unknown0
,
4756 return (STATUS_NOT_IMPLEMENTED
);
4760 /**********************************************************************
4765 * Creates a section object.
4768 * SectionObject (OUT)
4769 * Caller supplied storage for the resulting pointer
4770 * to a SECTION_OBJECT instance;
4773 * Specifies the desired access to the section can be a
4775 * STANDARD_RIGHTS_REQUIRED |
4777 * SECTION_MAP_WRITE |
4778 * SECTION_MAP_READ |
4779 * SECTION_MAP_EXECUTE
4781 * ObjectAttributes [OPTIONAL]
4782 * Initialized attributes for the object can be used
4783 * to create a named section;
4786 * Maximizes the size of the memory section. Must be
4787 * non-NULL for a page-file backed section.
4788 * If value specified for a mapped file and the file is
4789 * not large enough, file will be extended.
4791 * SectionPageProtection
4792 * Can be a combination of:
4798 * AllocationAttributes
4799 * Can be a combination of:
4804 * Handle to a file to create a section mapped to a file
4805 * instead of a memory backed section;
4816 MmCreateSection (OUT PVOID
* Section
,
4817 IN ACCESS_MASK DesiredAccess
,
4818 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4819 IN PLARGE_INTEGER MaximumSize
,
4820 IN ULONG SectionPageProtection
,
4821 IN ULONG AllocationAttributes
,
4822 IN HANDLE FileHandle OPTIONAL
,
4823 IN PFILE_OBJECT File OPTIONAL
)
4826 PSECTION_OBJECT
*SectionObject
= (PSECTION_OBJECT
*)Section
;
4829 * Check the protection
4831 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4832 if (Protection
!= PAGE_NOACCESS
&&
4833 Protection
!= PAGE_READONLY
&&
4834 Protection
!= PAGE_READWRITE
&&
4835 Protection
!= PAGE_WRITECOPY
&&
4836 Protection
!= PAGE_EXECUTE
&&
4837 Protection
!= PAGE_EXECUTE_READ
&&
4838 Protection
!= PAGE_EXECUTE_READWRITE
&&
4839 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4842 return STATUS_INVALID_PAGE_PROTECTION
;
4845 if (AllocationAttributes
& SEC_IMAGE
)
4847 return(MmCreateImageSection(SectionObject
,
4851 SectionPageProtection
,
4852 AllocationAttributes
,
4856 if (FileHandle
!= NULL
)
4858 return(MmCreateDataFileSection(SectionObject
,
4862 SectionPageProtection
,
4863 AllocationAttributes
,
4867 return(MmCreatePageFileSection(SectionObject
,
4871 SectionPageProtection
,
4872 AllocationAttributes
));