2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
49 #include <internal/debug.h>
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePool(ObjectNameInfo
);
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
155 * Filip says to get the MM_AVL_TABLE from EPROCESS,
156 * then use the MmMarea routines to locate the Marea that
157 * corresponds to the address. Then make sure it's a section
158 * view type (MEMORY_AREA_SECTION_VIEW) and use the marea's
159 * per-type union to get the .u.SectionView.Section pointer to
160 * the SECTION_OBJECT. Then we can use MmGetFileNameForSection
161 * to get the full filename.
163 RtlCreateUnicodeString(ModuleName
, L
"C:\\ReactOS\\system32\\ntdll.dll");
164 return STATUS_SUCCESS
;
167 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
170 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
171 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
172 * RETURNS: Status of the wait.
175 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
177 LARGE_INTEGER Timeout
;
178 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
180 Timeout
.QuadPart
= -100000000LL; // 10 sec
183 Timeout
.QuadPart
= -100000000; // 10 sec
186 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
191 * FUNCTION: Sets the page op completion event and releases the page op.
192 * ARGUMENTS: PMM_PAGEOP.
193 * RETURNS: In shorter time than it takes you to even read this
194 * description, so don't even think about geting a mug of coffee.
197 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
199 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
200 MmReleasePageOp(PageOp
);
205 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
206 * ARGUMENTS: PFILE_OBJECT to wait for.
207 * RETURNS: Status of the wait.
210 MmspWaitForFileLock(PFILE_OBJECT File
)
212 return STATUS_SUCCESS
;
213 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
218 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
221 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
223 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
225 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
227 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
235 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
237 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
239 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
240 PMM_SECTION_SEGMENT SectionSegments
;
244 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
245 NrSegments
= ImageSectionObject
->NrSegments
;
246 SectionSegments
= ImageSectionObject
->Segments
;
247 for (i
= 0; i
< NrSegments
; i
++)
249 if (SectionSegments
[i
].ReferenceCount
!= 0)
251 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
252 SectionSegments
[i
].ReferenceCount
);
255 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
257 ExFreePool(ImageSectionObject
->Segments
);
258 ExFreePool(ImageSectionObject
);
259 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
261 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
263 PMM_SECTION_SEGMENT Segment
;
265 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
268 if (Segment
->ReferenceCount
!= 0)
270 DPRINT1("Data segment still referenced\n");
273 MmFreePageTablesSectionSegment(Segment
);
275 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
281 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
283 ExAcquireFastMutex(&Segment
->Lock
);
288 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
290 ExReleaseFastMutex(&Segment
->Lock
);
295 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
299 PSECTION_PAGE_TABLE Table
;
300 ULONG DirectoryOffset
;
303 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
305 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
309 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
310 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
314 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
315 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
316 TAG_SECTION_PAGE_TABLE
);
321 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
322 DPRINT("Table %x\n", Table
);
325 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
326 Table
->Entry
[TableOffset
] = Entry
;
332 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
335 PSECTION_PAGE_TABLE Table
;
337 ULONG DirectoryOffset
;
340 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
342 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
344 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
348 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
349 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
350 DPRINT("Table %x\n", Table
);
356 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
357 Entry
= Table
->Entry
[TableOffset
];
363 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
368 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
371 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
374 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
376 DPRINT1("Maximum share count reached\n");
379 if (IS_SWAP_FROM_SSE(Entry
))
383 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
384 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
389 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
390 PMM_SECTION_SEGMENT Segment
,
396 BOOLEAN IsDirectMapped
= FALSE
;
398 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
401 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
404 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
406 DPRINT1("Zero share count for unshare\n");
409 if (IS_SWAP_FROM_SSE(Entry
))
413 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
415 * If we reducing the share count of this entry to zero then set the entry
416 * to zero and tell the cache the page is no longer mapped.
418 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
420 PFILE_OBJECT FileObject
;
422 SWAPENTRY SavedSwapEntry
;
424 BOOLEAN IsImageSection
;
427 FileOffset
= Offset
+ Segment
->FileOffset
;
429 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
431 Page
= PFN_FROM_SSE(Entry
);
432 FileObject
= Section
->FileObject
;
433 if (FileObject
!= NULL
&&
434 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
437 if ((FileOffset
% PAGE_SIZE
) == 0 &&
438 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
441 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
442 IsDirectMapped
= TRUE
;
443 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
444 if (!NT_SUCCESS(Status
))
446 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
452 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
453 if (SavedSwapEntry
== 0)
456 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
457 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
461 * Try to page out this page and set the swap entry
462 * within the section segment. There exist no rmap entry
463 * for this page. The pager thread can't page out a
464 * page without a rmap entry.
466 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
470 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
473 MmReleasePageMemoryConsumer(MC_USER
, Page
);
479 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
480 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
488 * We hold all locks. Nobody can do something with the current
489 * process and the current segment (also not within an other process).
492 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
493 if (!NT_SUCCESS(Status
))
495 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
499 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
500 MmSetSavedSwapEntryPage(Page
, 0);
502 MmReleasePageMemoryConsumer(MC_USER
, Page
);
506 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
513 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
515 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
518 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
521 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
524 PCACHE_SEGMENT CacheSeg
;
525 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
526 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
529 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
538 MiReadPage(PMEMORY_AREA MemoryArea
,
542 * FUNCTION: Read a page for a section backed memory area.
544 * MemoryArea - Memory area to read the page for.
545 * Offset - Offset of the page to read.
546 * Page - Variable that receives a page contains the read data.
553 PCACHE_SEGMENT CacheSeg
;
554 PFILE_OBJECT FileObject
;
558 BOOLEAN IsImageSection
;
561 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
562 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
563 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
564 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
565 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
569 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
572 * If the file system is letting us go directly to the cache and the
573 * memory area was mapped at an offset in the file which is page aligned
574 * then get the related cache segment.
576 if ((FileOffset
% PAGE_SIZE
) == 0 &&
577 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
578 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
582 * Get the related cache segment; we use a lower level interface than
583 * filesystems do because it is safe for us to use an offset with a
584 * alignment less than the file system block size.
586 Status
= CcRosGetCacheSegment(Bcb
,
592 if (!NT_SUCCESS(Status
))
599 * If the cache segment isn't up to date then call the file
600 * system to read in the data.
602 Status
= ReadCacheSegment(CacheSeg
);
603 if (!NT_SUCCESS(Status
))
605 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
610 * Retrieve the page from the cache segment that we actually want.
612 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
613 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
615 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
620 ULONG CacheSegOffset
;
622 * Allocate a page, this is rather complicated by the possibility
623 * we might have to move other things out of memory
625 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
626 if (!NT_SUCCESS(Status
))
630 Status
= CcRosGetCacheSegment(Bcb
,
636 if (!NT_SUCCESS(Status
))
643 * If the cache segment isn't up to date then call the file
644 * system to read in the data.
646 Status
= ReadCacheSegment(CacheSeg
);
647 if (!NT_SUCCESS(Status
))
649 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
653 PageAddr
= MmCreateHyperspaceMapping(*Page
);
654 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
655 Length
= RawLength
- SegOffset
;
656 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
658 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
660 else if (CacheSegOffset
>= PAGE_SIZE
)
662 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
666 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
667 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
668 Status
= CcRosGetCacheSegment(Bcb
,
669 FileOffset
+ CacheSegOffset
,
674 if (!NT_SUCCESS(Status
))
676 MmDeleteHyperspaceMapping(PageAddr
);
682 * If the cache segment isn't up to date then call the file
683 * system to read in the data.
685 Status
= ReadCacheSegment(CacheSeg
);
686 if (!NT_SUCCESS(Status
))
688 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
689 MmDeleteHyperspaceMapping(PageAddr
);
693 if (Length
< PAGE_SIZE
)
695 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
699 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
702 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
703 MmDeleteHyperspaceMapping(PageAddr
);
705 return(STATUS_SUCCESS
);
710 MmNotPresentFaultSectionView(PMM_AVL_TABLE AddressSpace
,
711 MEMORY_AREA
* MemoryArea
,
719 PROS_SECTION_OBJECT Section
;
720 PMM_SECTION_SEGMENT Segment
;
726 BOOLEAN HasSwapEntry
;
727 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
730 * There is a window between taking the page fault and locking the
731 * address space when another thread could load the page so we check
734 if (MmIsPagePresent(Process
, Address
))
738 MmLockPage(MmGetPfnForProcess(Process
, Address
));
740 return(STATUS_SUCCESS
);
743 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
744 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
745 + MemoryArea
->Data
.SectionData
.ViewOffset
;
747 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
748 Section
= MemoryArea
->Data
.SectionData
.Section
;
749 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
750 &MemoryArea
->Data
.SectionData
.RegionListHead
,
755 MmLockSectionSegment(Segment
);
758 * Check if this page needs to be mapped COW
760 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
761 (Region
->Protect
== PAGE_READWRITE
||
762 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
764 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
768 Attributes
= Region
->Protect
;
772 * Get or create a page operation descriptor
774 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
777 DPRINT1("MmGetPageOp failed\n");
782 * Check if someone else is already handling this fault, if so wait
785 if (PageOp
->Thread
!= PsGetCurrentThread())
787 MmUnlockSectionSegment(Segment
);
788 MmUnlockAddressSpace(AddressSpace
);
789 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
791 * Check for various strange conditions
793 if (Status
!= STATUS_SUCCESS
)
795 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
798 if (PageOp
->Status
== STATUS_PENDING
)
800 DPRINT1("Woke for page op before completion\n");
803 MmLockAddressSpace(AddressSpace
);
805 * If this wasn't a pagein then restart the operation
807 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
809 MmspCompleteAndReleasePageOp(PageOp
);
810 DPRINT("Address 0x%.8X\n", Address
);
811 return(STATUS_MM_RESTART_OPERATION
);
815 * If the thread handling this fault has failed then we don't retry
817 if (!NT_SUCCESS(PageOp
->Status
))
819 Status
= PageOp
->Status
;
820 MmspCompleteAndReleasePageOp(PageOp
);
821 DPRINT("Address 0x%.8X\n", Address
);
824 MmLockSectionSegment(Segment
);
826 * If the completed fault was for another address space then set the
829 if (!MmIsPagePresent(Process
, Address
))
831 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
832 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
834 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
837 * The page was a private page in another or in our address space
839 MmUnlockSectionSegment(Segment
);
840 MmspCompleteAndReleasePageOp(PageOp
);
841 return(STATUS_MM_RESTART_OPERATION
);
844 Page
= PFN_FROM_SSE(Entry
);
846 MmSharePageEntrySectionSegment(Segment
, Offset
);
848 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
849 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
851 Status
= MmCreateVirtualMapping(Process
,
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("Unable to create virtual mapping\n");
861 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
867 MmUnlockSectionSegment(Segment
);
868 PageOp
->Status
= STATUS_SUCCESS
;
869 MmspCompleteAndReleasePageOp(PageOp
);
870 DPRINT("Address 0x%.8X\n", Address
);
871 return(STATUS_SUCCESS
);
874 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
878 * Must be private page we have swapped out.
885 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
887 DPRINT1("Found a swaped out private page in a pagefile section.\n");
891 MmUnlockSectionSegment(Segment
);
892 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
894 MmUnlockAddressSpace(AddressSpace
);
895 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
896 if (!NT_SUCCESS(Status
))
901 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
902 if (!NT_SUCCESS(Status
))
904 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
907 MmLockAddressSpace(AddressSpace
);
908 Status
= MmCreateVirtualMapping(Process
,
913 if (!NT_SUCCESS(Status
))
915 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
921 * Store the swap entry for later use.
923 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
926 * Add the page to the process's working set
928 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
931 * Finish the operation
937 PageOp
->Status
= STATUS_SUCCESS
;
938 MmspCompleteAndReleasePageOp(PageOp
);
939 DPRINT("Address 0x%.8X\n", Address
);
940 return(STATUS_SUCCESS
);
944 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
946 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
948 MmUnlockSectionSegment(Segment
);
950 * Just map the desired physical page
952 Page
= Offset
>> PAGE_SHIFT
;
953 Status
= MmCreateVirtualMappingUnsafe(Process
,
958 if (!NT_SUCCESS(Status
))
960 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
965 * Don't add an rmap entry since the page mapped could be for
970 MmLockPageUnsafe(Page
);
974 * Cleanup and release locks
976 PageOp
->Status
= STATUS_SUCCESS
;
977 MmspCompleteAndReleasePageOp(PageOp
);
978 DPRINT("Address 0x%.8X\n", Address
);
979 return(STATUS_SUCCESS
);
983 * Map anonymous memory for BSS sections
985 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
987 MmUnlockSectionSegment(Segment
);
988 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
989 if (!NT_SUCCESS(Status
))
991 MmUnlockAddressSpace(AddressSpace
);
992 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
993 MmLockAddressSpace(AddressSpace
);
995 if (!NT_SUCCESS(Status
))
999 Status
= MmCreateVirtualMapping(Process
,
1004 if (!NT_SUCCESS(Status
))
1006 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1010 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1017 * Cleanup and release locks
1019 PageOp
->Status
= STATUS_SUCCESS
;
1020 MmspCompleteAndReleasePageOp(PageOp
);
1021 DPRINT("Address 0x%.8X\n", Address
);
1022 return(STATUS_SUCCESS
);
1026 * Get the entry corresponding to the offset within the section
1028 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1033 * If the entry is zero (and it can't change because we have
1034 * locked the segment) then we need to load the page.
1038 * Release all our locks and read in the page from disk
1040 MmUnlockSectionSegment(Segment
);
1041 MmUnlockAddressSpace(AddressSpace
);
1043 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1044 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1046 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1047 if (!NT_SUCCESS(Status
))
1049 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1054 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1055 if (!NT_SUCCESS(Status
))
1057 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1060 if (!NT_SUCCESS(Status
))
1063 * FIXME: What do we know in this case?
1066 * Cleanup and release locks
1068 MmLockAddressSpace(AddressSpace
);
1069 PageOp
->Status
= Status
;
1070 MmspCompleteAndReleasePageOp(PageOp
);
1071 DPRINT("Address 0x%.8X\n", Address
);
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 DPRINT1("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
);
1099 Status
= MmCreateVirtualMapping(Process
,
1104 if (!NT_SUCCESS(Status
))
1106 DPRINT1("Unable to create virtual mapping\n");
1109 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1115 PageOp
->Status
= STATUS_SUCCESS
;
1116 MmspCompleteAndReleasePageOp(PageOp
);
1117 DPRINT("Address 0x%.8X\n", Address
);
1118 return(STATUS_SUCCESS
);
1120 else if (IS_SWAP_FROM_SSE(Entry
))
1122 SWAPENTRY SwapEntry
;
1124 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1127 * Release all our locks and read in the page from disk
1129 MmUnlockSectionSegment(Segment
);
1131 MmUnlockAddressSpace(AddressSpace
);
1133 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1134 if (!NT_SUCCESS(Status
))
1139 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1140 if (!NT_SUCCESS(Status
))
1146 * Relock the address space and segment
1148 MmLockAddressSpace(AddressSpace
);
1149 MmLockSectionSegment(Segment
);
1152 * Check the entry. No one should change the status of a page
1153 * that has a pending page-in.
1155 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1156 if (Entry
!= Entry1
)
1158 DPRINT1("Someone changed ppte entry while we slept\n");
1163 * Mark the offset within the section as having valid, in-memory
1166 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1167 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1168 MmUnlockSectionSegment(Segment
);
1171 * Save the swap entry.
1173 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1174 Status
= MmCreateVirtualMapping(Process
,
1179 if (!NT_SUCCESS(Status
))
1181 DPRINT1("Unable to create virtual mapping\n");
1184 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1189 PageOp
->Status
= STATUS_SUCCESS
;
1190 MmspCompleteAndReleasePageOp(PageOp
);
1191 DPRINT("Address 0x%.8X\n", Address
);
1192 return(STATUS_SUCCESS
);
1197 * If the section offset is already in-memory and valid then just
1198 * take another reference to the page
1201 Page
= PFN_FROM_SSE(Entry
);
1203 MmSharePageEntrySectionSegment(Segment
, Offset
);
1204 MmUnlockSectionSegment(Segment
);
1206 Status
= MmCreateVirtualMapping(Process
,
1211 if (!NT_SUCCESS(Status
))
1213 DPRINT1("Unable to create virtual mapping\n");
1216 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1221 PageOp
->Status
= STATUS_SUCCESS
;
1222 MmspCompleteAndReleasePageOp(PageOp
);
1223 DPRINT("Address 0x%.8X\n", Address
);
1224 return(STATUS_SUCCESS
);
1230 MmAccessFaultSectionView(PMM_AVL_TABLE AddressSpace
,
1231 MEMORY_AREA
* MemoryArea
,
1235 PMM_SECTION_SEGMENT Segment
;
1236 PROS_SECTION_OBJECT Section
;
1245 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1247 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1250 * Check if the page has been paged out or has already been set readwrite
1252 if (!MmIsPagePresent(Process
, Address
) ||
1253 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1255 DPRINT("Address 0x%.8X\n", Address
);
1256 return(STATUS_SUCCESS
);
1260 * Find the offset of the page
1262 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1263 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1264 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1266 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1267 Section
= MemoryArea
->Data
.SectionData
.Section
;
1268 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1269 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1274 MmLockSectionSegment(Segment
);
1276 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1277 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1279 MmUnlockSectionSegment(Segment
);
1282 * Check if we are doing COW
1284 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1285 (Region
->Protect
== PAGE_READWRITE
||
1286 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1288 DPRINT("Address 0x%.8X\n", Address
);
1289 return(STATUS_UNSUCCESSFUL
);
1292 if (IS_SWAP_FROM_SSE(Entry
) ||
1293 PFN_FROM_SSE(Entry
) != OldPage
)
1295 /* This is a private page. We must only change the page protection. */
1296 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1297 return(STATUS_SUCCESS
);
1301 * Get or create a pageop
1303 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1304 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1307 DPRINT1("MmGetPageOp failed\n");
1312 * Wait for any other operations to complete
1314 if (PageOp
->Thread
!= PsGetCurrentThread())
1316 MmUnlockAddressSpace(AddressSpace
);
1317 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1319 * Check for various strange conditions
1321 if (Status
== STATUS_TIMEOUT
)
1323 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1326 if (PageOp
->Status
== STATUS_PENDING
)
1328 DPRINT1("Woke for page op before completion\n");
1332 * Restart the operation
1334 MmLockAddressSpace(AddressSpace
);
1335 MmspCompleteAndReleasePageOp(PageOp
);
1336 DPRINT("Address 0x%.8X\n", Address
);
1337 return(STATUS_MM_RESTART_OPERATION
);
1341 * Release locks now we have the pageop
1343 MmUnlockAddressSpace(AddressSpace
);
1348 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1349 if (!NT_SUCCESS(Status
))
1357 MiCopyFromUserPage(NewPage
, PAddress
);
1359 MmLockAddressSpace(AddressSpace
);
1361 * Delete the old entry.
1363 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1366 * Set the PTE to point to the new page
1368 Status
= MmCreateVirtualMapping(Process
,
1373 if (!NT_SUCCESS(Status
))
1375 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1379 if (!NT_SUCCESS(Status
))
1381 DPRINT1("Unable to create virtual mapping\n");
1386 MmLockPage(NewPage
);
1387 MmUnlockPage(OldPage
);
1391 * Unshare the old page.
1393 MmDeleteRmap(OldPage
, Process
, PAddress
);
1394 MmInsertRmap(NewPage
, Process
, PAddress
);
1395 MmLockSectionSegment(Segment
);
1396 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1397 MmUnlockSectionSegment(Segment
);
1399 PageOp
->Status
= STATUS_SUCCESS
;
1400 MmspCompleteAndReleasePageOp(PageOp
);
1401 DPRINT("Address 0x%.8X\n", Address
);
1402 return(STATUS_SUCCESS
);
1406 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1408 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1412 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1415 MmLockAddressSpace(&Process
->VadRoot
);
1418 MmDeleteVirtualMapping(Process
,
1425 PageOutContext
->WasDirty
= TRUE
;
1427 if (!PageOutContext
->Private
)
1429 MmLockSectionSegment(PageOutContext
->Segment
);
1430 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1431 PageOutContext
->Segment
,
1432 PageOutContext
->Offset
,
1433 PageOutContext
->WasDirty
,
1435 MmUnlockSectionSegment(PageOutContext
->Segment
);
1439 MmUnlockAddressSpace(&Process
->VadRoot
);
1442 if (PageOutContext
->Private
)
1444 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1447 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1452 MmPageOutSectionView(PMM_AVL_TABLE AddressSpace
,
1453 MEMORY_AREA
* MemoryArea
,
1458 MM_SECTION_PAGEOUT_CONTEXT Context
;
1459 SWAPENTRY SwapEntry
;
1463 PFILE_OBJECT FileObject
;
1465 BOOLEAN DirectMapped
;
1466 BOOLEAN IsImageSection
;
1467 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1469 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1472 * Get the segment and section.
1474 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1475 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1477 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1478 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1479 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1481 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1483 FileObject
= Context
.Section
->FileObject
;
1484 DirectMapped
= FALSE
;
1485 if (FileObject
!= NULL
&&
1486 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1488 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1491 * If the file system is letting us go directly to the cache and the
1492 * memory area was mapped at an offset in the file which is page aligned
1493 * then note this is a direct mapped page.
1495 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1496 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1498 DirectMapped
= TRUE
;
1504 * This should never happen since mappings of physical memory are never
1505 * placed in the rmap lists.
1507 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1509 DPRINT1("Trying to page out from physical memory section address 0x%X "
1510 "process %d\n", Address
,
1511 Process
? Process
->UniqueProcessId
: 0);
1516 * Get the section segment entry and the physical address.
1518 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1519 if (!MmIsPagePresent(Process
, Address
))
1521 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1522 Process
? Process
->UniqueProcessId
: 0, Address
);
1525 Page
= MmGetPfnForProcess(Process
, Address
);
1526 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1529 * Prepare the context structure for the rmap delete call.
1531 Context
.WasDirty
= FALSE
;
1532 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1533 IS_SWAP_FROM_SSE(Entry
) ||
1534 PFN_FROM_SSE(Entry
) != Page
)
1536 Context
.Private
= TRUE
;
1540 Context
.Private
= FALSE
;
1544 * Take an additional reference to the page or the cache segment.
1546 if (DirectMapped
&& !Context
.Private
)
1548 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1550 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1556 MmReferencePage(Page
);
1559 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1562 * If this wasn't a private page then we should have reduced the entry to
1563 * zero by deleting all the rmaps.
1565 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1567 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1568 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1575 * If the page wasn't dirty then we can just free it as for a readonly page.
1576 * Since we unmapped all the mappings above we know it will not suddenly
1578 * If the page is from a pagefile section and has no swap entry,
1579 * we can't free the page at this point.
1581 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1582 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1584 if (Context
.Private
)
1586 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1587 Context
.WasDirty
? "dirty" : "clean", Address
);
1590 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1592 MmSetSavedSwapEntryPage(Page
, 0);
1593 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1594 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1595 PageOp
->Status
= STATUS_SUCCESS
;
1596 MmspCompleteAndReleasePageOp(PageOp
);
1597 return(STATUS_SUCCESS
);
1600 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1602 if (Context
.Private
)
1604 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1605 Context
.WasDirty
? "dirty" : "clean", Address
);
1608 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1610 MmSetSavedSwapEntryPage(Page
, 0);
1613 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1615 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1616 PageOp
->Status
= STATUS_SUCCESS
;
1617 MmspCompleteAndReleasePageOp(PageOp
);
1618 return(STATUS_SUCCESS
);
1621 else if (!Context
.Private
&& DirectMapped
)
1625 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1629 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1635 PageOp
->Status
= STATUS_SUCCESS
;
1636 MmspCompleteAndReleasePageOp(PageOp
);
1637 return(STATUS_SUCCESS
);
1639 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1643 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1647 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1648 PageOp
->Status
= STATUS_SUCCESS
;
1649 MmspCompleteAndReleasePageOp(PageOp
);
1650 return(STATUS_SUCCESS
);
1652 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1654 MmSetSavedSwapEntryPage(Page
, 0);
1655 MmLockAddressSpace(AddressSpace
);
1656 Status
= MmCreatePageFileMapping(Process
,
1659 MmUnlockAddressSpace(AddressSpace
);
1660 if (!NT_SUCCESS(Status
))
1664 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1665 PageOp
->Status
= STATUS_SUCCESS
;
1666 MmspCompleteAndReleasePageOp(PageOp
);
1667 return(STATUS_SUCCESS
);
1671 * If necessary, allocate an entry in the paging file for this page
1675 SwapEntry
= MmAllocSwapPage();
1678 MmShowOutOfSpaceMessagePagingFile();
1679 MmLockAddressSpace(AddressSpace
);
1681 * For private pages restore the old mappings.
1683 if (Context
.Private
)
1685 Status
= MmCreateVirtualMapping(Process
,
1687 MemoryArea
->Protect
,
1690 MmSetDirtyPage(Process
, Address
);
1698 * For non-private pages if the page wasn't direct mapped then
1699 * set it back into the section segment entry so we don't loose
1700 * our copy. Otherwise it will be handled by the cache manager.
1702 Status
= MmCreateVirtualMapping(Process
,
1704 MemoryArea
->Protect
,
1707 MmSetDirtyPage(Process
, Address
);
1711 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1712 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1714 MmUnlockAddressSpace(AddressSpace
);
1715 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1716 MmspCompleteAndReleasePageOp(PageOp
);
1717 return(STATUS_PAGEFILE_QUOTA
);
1722 * Write the page to the pagefile
1724 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1725 if (!NT_SUCCESS(Status
))
1727 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1730 * As above: undo our actions.
1731 * FIXME: Also free the swap page.
1733 MmLockAddressSpace(AddressSpace
);
1734 if (Context
.Private
)
1736 Status
= MmCreateVirtualMapping(Process
,
1738 MemoryArea
->Protect
,
1741 MmSetDirtyPage(Process
, Address
);
1748 Status
= MmCreateVirtualMapping(Process
,
1750 MemoryArea
->Protect
,
1753 MmSetDirtyPage(Process
, Address
);
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1760 MmUnlockAddressSpace(AddressSpace
);
1761 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1762 MmspCompleteAndReleasePageOp(PageOp
);
1763 return(STATUS_UNSUCCESSFUL
);
1767 * Otherwise we have succeeded.
1769 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1770 MmSetSavedSwapEntryPage(Page
, 0);
1771 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1772 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1774 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1778 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1781 if (Context
.Private
)
1783 MmLockAddressSpace(AddressSpace
);
1784 Status
= MmCreatePageFileMapping(Process
,
1787 MmUnlockAddressSpace(AddressSpace
);
1788 if (!NT_SUCCESS(Status
))
1795 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1796 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1799 PageOp
->Status
= STATUS_SUCCESS
;
1800 MmspCompleteAndReleasePageOp(PageOp
);
1801 return(STATUS_SUCCESS
);
1806 MmWritePageSectionView(PMM_AVL_TABLE AddressSpace
,
1807 PMEMORY_AREA MemoryArea
,
1812 PROS_SECTION_OBJECT Section
;
1813 PMM_SECTION_SEGMENT Segment
;
1815 SWAPENTRY SwapEntry
;
1819 PFILE_OBJECT FileObject
;
1821 BOOLEAN DirectMapped
;
1822 BOOLEAN IsImageSection
;
1823 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1825 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1827 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1828 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1831 * Get the segment and section.
1833 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1834 Section
= MemoryArea
->Data
.SectionData
.Section
;
1835 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1837 FileObject
= Section
->FileObject
;
1838 DirectMapped
= FALSE
;
1839 if (FileObject
!= NULL
&&
1840 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1842 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1845 * If the file system is letting us go directly to the cache and the
1846 * memory area was mapped at an offset in the file which is page aligned
1847 * then note this is a direct mapped page.
1849 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1850 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1852 DirectMapped
= TRUE
;
1857 * This should never happen since mappings of physical memory are never
1858 * placed in the rmap lists.
1860 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1862 DPRINT1("Trying to write back page from physical memory mapped at %X "
1863 "process %d\n", Address
,
1864 Process
? Process
->UniqueProcessId
: 0);
1869 * Get the section segment entry and the physical address.
1871 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1872 if (!MmIsPagePresent(Process
, Address
))
1874 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1875 Process
? Process
->UniqueProcessId
: 0, Address
);
1878 Page
= MmGetPfnForProcess(Process
, Address
);
1879 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1882 * Check for a private (COWed) page.
1884 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1885 IS_SWAP_FROM_SSE(Entry
) ||
1886 PFN_FROM_SSE(Entry
) != Page
)
1896 * Speculatively set all mappings of the page to clean.
1898 MmSetCleanAllRmaps(Page
);
1901 * If this page was direct mapped from the cache then the cache manager
1902 * will take care of writing it back to disk.
1904 if (DirectMapped
&& !Private
)
1906 ASSERT(SwapEntry
== 0);
1907 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1908 PageOp
->Status
= STATUS_SUCCESS
;
1909 MmspCompleteAndReleasePageOp(PageOp
);
1910 return(STATUS_SUCCESS
);
1914 * If necessary, allocate an entry in the paging file for this page
1918 SwapEntry
= MmAllocSwapPage();
1921 MmSetDirtyAllRmaps(Page
);
1922 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1923 MmspCompleteAndReleasePageOp(PageOp
);
1924 return(STATUS_PAGEFILE_QUOTA
);
1926 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1930 * Write the page to the pagefile
1932 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1933 if (!NT_SUCCESS(Status
))
1935 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1937 MmSetDirtyAllRmaps(Page
);
1938 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1939 MmspCompleteAndReleasePageOp(PageOp
);
1940 return(STATUS_UNSUCCESSFUL
);
1944 * Otherwise we have succeeded.
1946 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1947 PageOp
->Status
= STATUS_SUCCESS
;
1948 MmspCompleteAndReleasePageOp(PageOp
);
1949 return(STATUS_SUCCESS
);
1953 MmAlterViewAttributes(PMM_AVL_TABLE AddressSpace
,
1961 PMEMORY_AREA MemoryArea
;
1962 PMM_SECTION_SEGMENT Segment
;
1963 BOOLEAN DoCOW
= FALSE
;
1965 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1967 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1968 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1970 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1971 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1976 if (OldProtect
!= NewProtect
)
1978 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1980 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1981 ULONG Protect
= NewProtect
;
1984 * If we doing COW for this segment then check if the page is
1987 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
1993 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1994 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1995 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1996 Page
= MmGetPfnForProcess(Process
, Address
);
1998 Protect
= PAGE_READONLY
;
1999 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2000 IS_SWAP_FROM_SSE(Entry
) ||
2001 PFN_FROM_SSE(Entry
) != Page
)
2003 Protect
= NewProtect
;
2007 if (MmIsPagePresent(Process
, Address
))
2009 MmSetPageProtect(Process
, Address
,
2018 MmProtectSectionView(PMM_AVL_TABLE AddressSpace
,
2019 PMEMORY_AREA MemoryArea
,
2027 ULONG_PTR MaxLength
;
2029 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2030 if (Length
> MaxLength
)
2033 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2034 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2036 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2037 Region
->Protect
!= Protect
)
2040 return STATUS_INVALID_PAGE_PROTECTION
;
2043 *OldProtect
= Region
->Protect
;
2044 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2045 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2046 BaseAddress
, Length
, Region
->Type
, Protect
,
2047 MmAlterViewAttributes
);
2053 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2055 PMEMORY_BASIC_INFORMATION Info
,
2056 PULONG ResultLength
)
2059 PVOID RegionBaseAddress
;
2060 PROS_SECTION_OBJECT Section
;
2061 PMM_SECTION_SEGMENT Segment
;
2063 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2064 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2065 Address
, &RegionBaseAddress
);
2068 return STATUS_UNSUCCESSFUL
;
2071 Section
= MemoryArea
->Data
.SectionData
.Section
;
2072 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2074 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2075 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2076 Info
->Type
= MEM_IMAGE
;
2080 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2081 Info
->Type
= MEM_MAPPED
;
2083 Info
->BaseAddress
= RegionBaseAddress
;
2084 Info
->AllocationProtect
= MemoryArea
->Protect
;
2085 Info
->RegionSize
= Region
->Length
;
2086 Info
->State
= MEM_COMMIT
;
2087 Info
->Protect
= Region
->Protect
;
2089 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2090 return(STATUS_SUCCESS
);
2095 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2100 ULONG SavedSwapEntry
;
2105 Length
= PAGE_ROUND_UP(Segment
->Length
);
2106 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2108 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2111 if (IS_SWAP_FROM_SSE(Entry
))
2113 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2117 Page
= PFN_FROM_SSE(Entry
);
2118 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2119 if (SavedSwapEntry
!= 0)
2121 MmSetSavedSwapEntryPage(Page
, 0);
2122 MmFreeSwapPage(SavedSwapEntry
);
2124 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2126 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2132 MmpDeleteSection(PVOID ObjectBody
)
2134 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2136 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2137 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2142 PMM_SECTION_SEGMENT SectionSegments
;
2145 * NOTE: Section->ImageSection can be NULL for short time
2146 * during the section creating. If we fail for some reason
2147 * until the image section is properly initialized we shouldn't
2148 * process further here.
2150 if (Section
->ImageSection
== NULL
)
2153 SectionSegments
= Section
->ImageSection
->Segments
;
2154 NrSegments
= Section
->ImageSection
->NrSegments
;
2156 for (i
= 0; i
< NrSegments
; i
++)
2158 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2160 MmLockSectionSegment(&SectionSegments
[i
]);
2162 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2163 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2167 MmpFreePageFileSegment(&SectionSegments
[i
]);
2169 MmUnlockSectionSegment(&SectionSegments
[i
]);
2176 * NOTE: Section->Segment can be NULL for short time
2177 * during the section creating.
2179 if (Section
->Segment
== NULL
)
2182 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2184 MmpFreePageFileSegment(Section
->Segment
);
2185 MmFreePageTablesSectionSegment(Section
->Segment
);
2186 ExFreePool(Section
->Segment
);
2187 Section
->Segment
= NULL
;
2191 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2194 if (Section
->FileObject
!= NULL
)
2196 CcRosDereferenceCache(Section
->FileObject
);
2197 ObDereferenceObject(Section
->FileObject
);
2198 Section
->FileObject
= NULL
;
2203 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2205 IN ACCESS_MASK GrantedAccess
,
2206 IN ULONG ProcessHandleCount
,
2207 IN ULONG SystemHandleCount
)
2209 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2210 Object
, ProcessHandleCount
);
2216 MmCreatePhysicalMemorySection(VOID
)
2218 PROS_SECTION_OBJECT PhysSection
;
2220 OBJECT_ATTRIBUTES Obj
;
2221 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2222 LARGE_INTEGER SectionSize
;
2226 * Create the section mapping physical memory
2228 SectionSize
.QuadPart
= 0xFFFFFFFF;
2229 InitializeObjectAttributes(&Obj
,
2234 Status
= MmCreateSection((PVOID
)&PhysSection
,
2238 PAGE_EXECUTE_READWRITE
,
2242 if (!NT_SUCCESS(Status
))
2244 DPRINT1("Failed to create PhysicalMemory section\n");
2247 Status
= ObInsertObject(PhysSection
,
2253 if (!NT_SUCCESS(Status
))
2255 ObDereferenceObject(PhysSection
);
2257 ObCloseHandle(Handle
, KernelMode
);
2258 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2259 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2261 return(STATUS_SUCCESS
);
2267 MmInitSectionImplementation(VOID
)
2269 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2270 UNICODE_STRING Name
;
2272 DPRINT("Creating Section Object Type\n");
2274 /* Initialize the Section object type */
2275 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2276 RtlInitUnicodeString(&Name
, L
"Section");
2277 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2278 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2279 ObjectTypeInitializer
.PoolType
= PagedPool
;
2280 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2281 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2282 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2283 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2284 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2285 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2287 return(STATUS_SUCCESS
);
2292 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2293 ACCESS_MASK DesiredAccess
,
2294 POBJECT_ATTRIBUTES ObjectAttributes
,
2295 PLARGE_INTEGER UMaximumSize
,
2296 ULONG SectionPageProtection
,
2297 ULONG AllocationAttributes
)
2299 * Create a section which is backed by the pagefile
2302 LARGE_INTEGER MaximumSize
;
2303 PROS_SECTION_OBJECT Section
;
2304 PMM_SECTION_SEGMENT Segment
;
2307 if (UMaximumSize
== NULL
)
2309 return(STATUS_UNSUCCESSFUL
);
2311 MaximumSize
= *UMaximumSize
;
2314 * Create the section
2316 Status
= ObCreateObject(ExGetPreviousMode(),
2317 MmSectionObjectType
,
2319 ExGetPreviousMode(),
2321 sizeof(ROS_SECTION_OBJECT
),
2324 (PVOID
*)(PVOID
)&Section
);
2325 if (!NT_SUCCESS(Status
))
2333 Section
->SectionPageProtection
= SectionPageProtection
;
2334 Section
->AllocationAttributes
= AllocationAttributes
;
2335 Section
->Segment
= NULL
;
2336 Section
->FileObject
= NULL
;
2337 Section
->MaximumSize
= MaximumSize
;
2338 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2339 TAG_MM_SECTION_SEGMENT
);
2340 if (Segment
== NULL
)
2342 ObDereferenceObject(Section
);
2343 return(STATUS_NO_MEMORY
);
2345 Section
->Segment
= Segment
;
2346 Segment
->ReferenceCount
= 1;
2347 ExInitializeFastMutex(&Segment
->Lock
);
2348 Segment
->FileOffset
= 0;
2349 Segment
->Protection
= SectionPageProtection
;
2350 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2351 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2352 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2353 Segment
->WriteCopy
= FALSE
;
2354 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2355 Segment
->VirtualAddress
= 0;
2356 Segment
->Characteristics
= 0;
2357 *SectionObject
= Section
;
2358 return(STATUS_SUCCESS
);
2364 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2365 ACCESS_MASK DesiredAccess
,
2366 POBJECT_ATTRIBUTES ObjectAttributes
,
2367 PLARGE_INTEGER UMaximumSize
,
2368 ULONG SectionPageProtection
,
2369 ULONG AllocationAttributes
,
2372 * Create a section backed by a data file
2375 PROS_SECTION_OBJECT Section
;
2377 LARGE_INTEGER MaximumSize
;
2378 PFILE_OBJECT FileObject
;
2379 PMM_SECTION_SEGMENT Segment
;
2381 IO_STATUS_BLOCK Iosb
;
2382 LARGE_INTEGER Offset
;
2384 FILE_STANDARD_INFORMATION FileInfo
;
2387 * Create the section
2389 Status
= ObCreateObject(ExGetPreviousMode(),
2390 MmSectionObjectType
,
2392 ExGetPreviousMode(),
2394 sizeof(ROS_SECTION_OBJECT
),
2397 (PVOID
*)(PVOID
)&Section
);
2398 if (!NT_SUCCESS(Status
))
2405 Section
->SectionPageProtection
= SectionPageProtection
;
2406 Section
->AllocationAttributes
= AllocationAttributes
;
2407 Section
->Segment
= NULL
;
2410 * Check file access required
2412 if (SectionPageProtection
& PAGE_READWRITE
||
2413 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2415 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2419 FileAccess
= FILE_READ_DATA
;
2423 * Reference the file handle
2425 Status
= ObReferenceObjectByHandle(FileHandle
,
2428 ExGetPreviousMode(),
2429 (PVOID
*)(PVOID
)&FileObject
,
2431 if (!NT_SUCCESS(Status
))
2433 ObDereferenceObject(Section
);
2438 * FIXME: This is propably not entirely correct. We can't look into
2439 * the standard FCB header because it might not be initialized yet
2440 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2441 * standard file information is filled on first request).
2443 Status
= IoQueryFileInformation(FileObject
,
2444 FileStandardInformation
,
2445 sizeof(FILE_STANDARD_INFORMATION
),
2448 if (!NT_SUCCESS(Status
))
2450 ObDereferenceObject(Section
);
2451 ObDereferenceObject(FileObject
);
2456 * FIXME: Revise this once a locking order for file size changes is
2459 if (UMaximumSize
!= NULL
)
2461 MaximumSize
= *UMaximumSize
;
2465 MaximumSize
= FileInfo
.EndOfFile
;
2466 /* Mapping zero-sized files isn't allowed. */
2467 if (MaximumSize
.QuadPart
== 0)
2469 ObDereferenceObject(Section
);
2470 ObDereferenceObject(FileObject
);
2471 return STATUS_FILE_INVALID
;
2475 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2477 Status
= IoSetInformation(FileObject
,
2478 FileAllocationInformation
,
2479 sizeof(LARGE_INTEGER
),
2481 if (!NT_SUCCESS(Status
))
2483 ObDereferenceObject(Section
);
2484 ObDereferenceObject(FileObject
);
2485 return(STATUS_SECTION_NOT_EXTENDED
);
2489 if (FileObject
->SectionObjectPointer
== NULL
||
2490 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2493 * Read a bit so caching is initiated for the file object.
2494 * This is only needed because MiReadPage currently cannot
2495 * handle non-cached streams.
2497 Offset
.QuadPart
= 0;
2498 Status
= ZwReadFile(FileHandle
,
2507 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2509 ObDereferenceObject(Section
);
2510 ObDereferenceObject(FileObject
);
2513 if (FileObject
->SectionObjectPointer
== NULL
||
2514 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2516 /* FIXME: handle this situation */
2517 ObDereferenceObject(Section
);
2518 ObDereferenceObject(FileObject
);
2519 return STATUS_INVALID_PARAMETER
;
2526 Status
= MmspWaitForFileLock(FileObject
);
2527 if (Status
!= STATUS_SUCCESS
)
2529 ObDereferenceObject(Section
);
2530 ObDereferenceObject(FileObject
);
2535 * If this file hasn't been mapped as a data file before then allocate a
2536 * section segment to describe the data file mapping
2538 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2540 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2541 TAG_MM_SECTION_SEGMENT
);
2542 if (Segment
== NULL
)
2544 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2545 ObDereferenceObject(Section
);
2546 ObDereferenceObject(FileObject
);
2547 return(STATUS_NO_MEMORY
);
2549 Section
->Segment
= Segment
;
2550 Segment
->ReferenceCount
= 1;
2551 ExInitializeFastMutex(&Segment
->Lock
);
2553 * Set the lock before assigning the segment to the file object
2555 ExAcquireFastMutex(&Segment
->Lock
);
2556 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2558 Segment
->FileOffset
= 0;
2559 Segment
->Protection
= SectionPageProtection
;
2560 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2561 Segment
->Characteristics
= 0;
2562 Segment
->WriteCopy
= FALSE
;
2563 if (AllocationAttributes
& SEC_RESERVE
)
2565 Segment
->Length
= Segment
->RawLength
= 0;
2569 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2570 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2572 Segment
->VirtualAddress
= 0;
2573 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2578 * If the file is already mapped as a data file then we may need
2582 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2584 Section
->Segment
= Segment
;
2585 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2586 MmLockSectionSegment(Segment
);
2588 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2589 !(AllocationAttributes
& SEC_RESERVE
))
2591 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2592 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2595 MmUnlockSectionSegment(Segment
);
2596 Section
->FileObject
= FileObject
;
2597 Section
->MaximumSize
= MaximumSize
;
2598 CcRosReferenceCache(FileObject
);
2599 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2600 *SectionObject
= Section
;
2601 return(STATUS_SUCCESS
);
2605 TODO: not that great (declaring loaders statically, having to declare all of
2606 them, having to keep them extern, etc.), will fix in the future
2608 extern NTSTATUS NTAPI PeFmtCreateSection
2610 IN CONST VOID
* FileHeader
,
2611 IN SIZE_T FileHeaderSize
,
2613 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2615 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2616 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2619 extern NTSTATUS NTAPI ElfFmtCreateSection
2621 IN CONST VOID
* FileHeader
,
2622 IN SIZE_T FileHeaderSize
,
2624 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2626 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2627 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2630 /* TODO: this is a standard DDK/PSDK macro */
2631 #ifndef RTL_NUMBER_OF
2632 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2635 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2646 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2648 SIZE_T SizeOfSegments
;
2649 PMM_SECTION_SEGMENT Segments
;
2651 /* TODO: check for integer overflow */
2652 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2654 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2656 TAG_MM_SECTION_SEGMENT
);
2659 RtlZeroMemory(Segments
, SizeOfSegments
);
2667 ExeFmtpReadFile(IN PVOID File
,
2668 IN PLARGE_INTEGER Offset
,
2671 OUT PVOID
* AllocBase
,
2672 OUT PULONG ReadSize
)
2675 LARGE_INTEGER FileOffset
;
2677 ULONG OffsetAdjustment
;
2682 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2686 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2689 FileOffset
= *Offset
;
2691 /* Negative/special offset: it cannot be used in this context */
2692 if(FileOffset
.u
.HighPart
< 0)
2694 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2697 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2698 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2699 FileOffset
.u
.LowPart
= AdjustOffset
;
2701 BufferSize
= Length
+ OffsetAdjustment
;
2702 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2705 * It's ok to use paged pool, because this is a temporary buffer only used in
2706 * the loading of executables. The assumption is that MmCreateSection is
2707 * always called at low IRQLs and that these buffers don't survive a brief
2708 * initialization phase
2710 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2712 TAG('M', 'm', 'X', 'r'));
2717 Status
= MmspPageRead(File
,
2724 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2725 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2726 * to initialize internal state is even worse. Our cache manager is in need of
2730 IO_STATUS_BLOCK Iosb
;
2732 Status
= ZwReadFile(File
,
2742 if(NT_SUCCESS(Status
))
2744 UsedSize
= Iosb
.Information
;
2749 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2751 Status
= STATUS_IN_PAGE_ERROR
;
2752 ASSERT(!NT_SUCCESS(Status
));
2755 if(NT_SUCCESS(Status
))
2757 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2758 *AllocBase
= Buffer
;
2759 *ReadSize
= UsedSize
- OffsetAdjustment
;
2770 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2771 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2772 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2777 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2781 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2783 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2784 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2791 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2795 MmspAssertSegmentsSorted(ImageSectionObject
);
2797 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2799 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2803 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2804 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2805 ImageSectionObject
->Segments
[i
- 1].Length
));
2813 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2817 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2819 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2820 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2828 MmspCompareSegments(const void * x
,
2831 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2832 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2835 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2836 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2840 * Ensures an image section's segments are sorted in memory
2845 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2848 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2850 MmspAssertSegmentsSorted(ImageSectionObject
);
2854 qsort(ImageSectionObject
->Segments
,
2855 ImageSectionObject
->NrSegments
,
2856 sizeof(ImageSectionObject
->Segments
[0]),
2857 MmspCompareSegments
);
2863 * Ensures an image section's segments don't overlap in memory and don't have
2864 * gaps and don't have a null size. We let them map to overlapping file regions,
2865 * though - that's not necessarily an error
2870 MmspCheckSegmentBounds
2872 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2878 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2880 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2884 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2886 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2888 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2896 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2897 * page could be OK (Windows seems to be OK with them), and larger gaps
2898 * could lead to image sections spanning several discontiguous regions
2899 * (NtMapViewOfSection could then refuse to map them, and they could
2900 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2902 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2903 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2904 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2915 * Merges and pads an image section's segments until they all are page-aligned
2916 * and have a size that is a multiple of the page size
2921 MmspPageAlignSegments
2923 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2929 BOOLEAN Initialized
;
2930 PMM_SECTION_SEGMENT EffectiveSegment
;
2932 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2934 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2938 Initialized
= FALSE
;
2940 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2942 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2945 * The first segment requires special handling
2949 ULONG_PTR VirtualAddress
;
2950 ULONG_PTR VirtualOffset
;
2952 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2954 /* Round down the virtual address to the nearest page */
2955 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2957 /* Round up the virtual size to the nearest page */
2958 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2959 EffectiveSegment
->VirtualAddress
;
2961 /* Adjust the raw address and size */
2962 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2964 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2970 * Garbage in, garbage out: unaligned base addresses make the file
2971 * offset point in curious and odd places, but that's what we were
2974 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2975 EffectiveSegment
->RawLength
+= VirtualOffset
;
2979 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2980 ULONG_PTR EndOfEffectiveSegment
;
2982 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2983 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2986 * The current segment begins exactly where the current effective
2987 * segment ended, therefore beginning a new effective segment
2989 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2992 ASSERT(LastSegment
<= i
);
2993 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2995 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2997 if (LastSegment
!= i
)
3000 * Copy the current segment. If necessary, the effective segment
3001 * will be expanded later
3003 *EffectiveSegment
= *Segment
;
3007 * Page-align the virtual size. We know for sure the virtual address
3010 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3011 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3014 * The current segment is still part of the current effective segment:
3015 * extend the effective segment to reflect this
3017 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3019 static const ULONG FlagsToProtection
[16] =
3027 PAGE_EXECUTE_READWRITE
,
3028 PAGE_EXECUTE_READWRITE
,
3033 PAGE_EXECUTE_WRITECOPY
,
3034 PAGE_EXECUTE_WRITECOPY
,
3035 PAGE_EXECUTE_WRITECOPY
,
3036 PAGE_EXECUTE_WRITECOPY
3039 unsigned ProtectionFlags
;
3042 * Extend the file size
3045 /* Unaligned segments must be contiguous within the file */
3046 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3047 EffectiveSegment
->RawLength
))
3052 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3055 * Extend the virtual size
3057 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3059 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3060 EffectiveSegment
->VirtualAddress
;
3063 * Merge the protection
3065 EffectiveSegment
->Protection
|= Segment
->Protection
;
3067 /* Clean up redundance */
3068 ProtectionFlags
= 0;
3070 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3071 ProtectionFlags
|= 1 << 0;
3073 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3074 ProtectionFlags
|= 1 << 1;
3076 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3077 ProtectionFlags
|= 1 << 2;
3079 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3080 ProtectionFlags
|= 1 << 3;
3082 ASSERT(ProtectionFlags
< 16);
3083 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3085 /* If a segment was required to be shared and cannot, fail */
3086 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3087 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3093 * We assume no holes between segments at this point
3101 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3107 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3108 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3110 LARGE_INTEGER Offset
;
3112 PVOID FileHeaderBuffer
;
3113 ULONG FileHeaderSize
;
3115 ULONG OldNrSegments
;
3120 * Read the beginning of the file (2 pages). Should be enough to contain
3121 * all (or most) of the headers
3123 Offset
.QuadPart
= 0;
3125 /* FIXME: use FileObject instead of FileHandle */
3126 Status
= ExeFmtpReadFile (FileHandle
,
3133 if (!NT_SUCCESS(Status
))
3136 if (FileHeaderSize
== 0)
3138 ExFreePool(FileHeaderBuffer
);
3139 return STATUS_UNSUCCESSFUL
;
3143 * Look for a loader that can handle this executable
3145 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3147 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3150 /* FIXME: use FileObject instead of FileHandle */
3151 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3157 ExeFmtpAllocateSegments
);
3159 if (!NT_SUCCESS(Status
))
3161 if (ImageSectionObject
->Segments
)
3163 ExFreePool(ImageSectionObject
->Segments
);
3164 ImageSectionObject
->Segments
= NULL
;
3168 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3172 ExFreePool(FileHeaderBuffer
);
3175 * No loader handled the format
3177 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3179 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3180 ASSERT(!NT_SUCCESS(Status
));
3183 if (!NT_SUCCESS(Status
))
3186 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3191 /* FIXME? are these values platform-dependent? */
3192 if(ImageSectionObject
->StackReserve
== 0)
3193 ImageSectionObject
->StackReserve
= 0x40000;
3195 if(ImageSectionObject
->StackCommit
== 0)
3196 ImageSectionObject
->StackCommit
= 0x1000;
3198 if(ImageSectionObject
->ImageBase
== 0)
3200 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3201 ImageSectionObject
->ImageBase
= 0x10000000;
3203 ImageSectionObject
->ImageBase
= 0x00400000;
3207 * And now the fun part: fixing the segments
3210 /* Sort them by virtual address */
3211 MmspSortSegments(ImageSectionObject
, Flags
);
3213 /* Ensure they don't overlap in memory */
3214 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3215 return STATUS_INVALID_IMAGE_FORMAT
;
3217 /* Ensure they are aligned */
3218 OldNrSegments
= ImageSectionObject
->NrSegments
;
3220 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3221 return STATUS_INVALID_IMAGE_FORMAT
;
3223 /* Trim them if the alignment phase merged some of them */
3224 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3226 PMM_SECTION_SEGMENT Segments
;
3227 SIZE_T SizeOfSegments
;
3229 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3231 Segments
= ExAllocatePoolWithTag(PagedPool
,
3233 TAG_MM_SECTION_SEGMENT
);
3235 if (Segments
== NULL
)
3236 return STATUS_INSUFFICIENT_RESOURCES
;
3238 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3239 ExFreePool(ImageSectionObject
->Segments
);
3240 ImageSectionObject
->Segments
= Segments
;
3243 /* And finish their initialization */
3244 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3246 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3247 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3249 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3250 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3253 ASSERT(NT_SUCCESS(Status
));
3258 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3259 ACCESS_MASK DesiredAccess
,
3260 POBJECT_ATTRIBUTES ObjectAttributes
,
3261 PLARGE_INTEGER UMaximumSize
,
3262 ULONG SectionPageProtection
,
3263 ULONG AllocationAttributes
,
3266 PROS_SECTION_OBJECT Section
;
3268 PFILE_OBJECT FileObject
;
3269 PMM_SECTION_SEGMENT SectionSegments
;
3270 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3272 ULONG FileAccess
= 0;
3275 * Specifying a maximum size is meaningless for an image section
3277 if (UMaximumSize
!= NULL
)
3279 return(STATUS_INVALID_PARAMETER_4
);
3283 * Check file access required
3285 if (SectionPageProtection
& PAGE_READWRITE
||
3286 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3288 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3292 FileAccess
= FILE_READ_DATA
;
3296 * Reference the file handle
3298 Status
= ObReferenceObjectByHandle(FileHandle
,
3301 ExGetPreviousMode(),
3302 (PVOID
*)(PVOID
)&FileObject
,
3305 if (!NT_SUCCESS(Status
))
3311 * Create the section
3313 Status
= ObCreateObject (ExGetPreviousMode(),
3314 MmSectionObjectType
,
3316 ExGetPreviousMode(),
3318 sizeof(ROS_SECTION_OBJECT
),
3321 (PVOID
*)(PVOID
)&Section
);
3322 if (!NT_SUCCESS(Status
))
3324 ObDereferenceObject(FileObject
);
3331 Section
->SectionPageProtection
= SectionPageProtection
;
3332 Section
->AllocationAttributes
= AllocationAttributes
;
3335 * Initialized caching for this file object if previously caching
3336 * was initialized for the same on disk file
3338 Status
= CcTryToInitializeFileCache(FileObject
);
3340 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3342 NTSTATUS StatusExeFmt
;
3344 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3345 if (ImageSectionObject
== NULL
)
3347 ObDereferenceObject(FileObject
);
3348 ObDereferenceObject(Section
);
3349 return(STATUS_NO_MEMORY
);
3352 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3354 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3356 if (!NT_SUCCESS(StatusExeFmt
))
3358 if(ImageSectionObject
->Segments
!= NULL
)
3359 ExFreePool(ImageSectionObject
->Segments
);
3361 ExFreePool(ImageSectionObject
);
3362 ObDereferenceObject(Section
);
3363 ObDereferenceObject(FileObject
);
3364 return(StatusExeFmt
);
3367 Section
->ImageSection
= ImageSectionObject
;
3368 ASSERT(ImageSectionObject
->Segments
);
3373 Status
= MmspWaitForFileLock(FileObject
);
3374 if (!NT_SUCCESS(Status
))
3376 ExFreePool(ImageSectionObject
->Segments
);
3377 ExFreePool(ImageSectionObject
);
3378 ObDereferenceObject(Section
);
3379 ObDereferenceObject(FileObject
);
3383 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3384 ImageSectionObject
, NULL
))
3387 * An other thread has initialized the some image in the background
3389 ExFreePool(ImageSectionObject
->Segments
);
3390 ExFreePool(ImageSectionObject
);
3391 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3392 Section
->ImageSection
= ImageSectionObject
;
3393 SectionSegments
= ImageSectionObject
->Segments
;
3395 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3397 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3401 Status
= StatusExeFmt
;
3408 Status
= MmspWaitForFileLock(FileObject
);
3409 if (Status
!= STATUS_SUCCESS
)
3411 ObDereferenceObject(Section
);
3412 ObDereferenceObject(FileObject
);
3416 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3417 Section
->ImageSection
= ImageSectionObject
;
3418 SectionSegments
= ImageSectionObject
->Segments
;
3421 * Otherwise just reference all the section segments
3423 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3425 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3428 Status
= STATUS_SUCCESS
;
3430 Section
->FileObject
= FileObject
;
3431 CcRosReferenceCache(FileObject
);
3432 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3433 *SectionObject
= Section
;
3441 NtCreateSection (OUT PHANDLE SectionHandle
,
3442 IN ACCESS_MASK DesiredAccess
,
3443 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3444 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3445 IN ULONG SectionPageProtection OPTIONAL
,
3446 IN ULONG AllocationAttributes
,
3447 IN HANDLE FileHandle OPTIONAL
)
3449 LARGE_INTEGER SafeMaximumSize
;
3450 PVOID SectionObject
;
3451 KPROCESSOR_MODE PreviousMode
;
3452 NTSTATUS Status
= STATUS_SUCCESS
;
3454 PreviousMode
= ExGetPreviousMode();
3456 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3460 /* make a copy on the stack */
3461 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3462 MaximumSize
= &SafeMaximumSize
;
3466 Status
= _SEH_GetExceptionCode();
3470 if(!NT_SUCCESS(Status
))
3476 Status
= MmCreateSection(&SectionObject
,
3480 SectionPageProtection
,
3481 AllocationAttributes
,
3484 if (NT_SUCCESS(Status
))
3486 Status
= ObInsertObject ((PVOID
)SectionObject
,
3498 /**********************************************************************
3516 NtOpenSection(PHANDLE SectionHandle
,
3517 ACCESS_MASK DesiredAccess
,
3518 POBJECT_ATTRIBUTES ObjectAttributes
)
3521 KPROCESSOR_MODE PreviousMode
;
3522 NTSTATUS Status
= STATUS_SUCCESS
;
3524 PreviousMode
= ExGetPreviousMode();
3526 if(PreviousMode
!= KernelMode
)
3530 ProbeForWriteHandle(SectionHandle
);
3534 Status
= _SEH_GetExceptionCode();
3538 if(!NT_SUCCESS(Status
))
3544 Status
= ObOpenObjectByName(ObjectAttributes
,
3545 MmSectionObjectType
,
3552 if(NT_SUCCESS(Status
))
3556 *SectionHandle
= hSection
;
3560 Status
= _SEH_GetExceptionCode();
3569 MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3570 PROS_SECTION_OBJECT Section
,
3571 PMM_SECTION_SEGMENT Segment
,
3576 ULONG AllocationType
)
3580 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3582 BoundaryAddressMultiple
.QuadPart
= 0;
3584 Status
= MmCreateMemoryArea(AddressSpace
,
3585 MEMORY_AREA_SECTION_VIEW
,
3592 BoundaryAddressMultiple
);
3593 if (!NT_SUCCESS(Status
))
3595 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3596 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3600 ObReferenceObject((PVOID
)Section
);
3602 MArea
->Data
.SectionData
.Segment
= Segment
;
3603 MArea
->Data
.SectionData
.Section
= Section
;
3604 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3605 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3606 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3607 ViewSize
, 0, Protect
);
3609 return(STATUS_SUCCESS
);
3613 /**********************************************************************
3615 * NtMapViewOfSection
3618 * Maps a view of a section into the virtual address space of a
3623 * Handle of the section.
3626 * Handle of the process.
3629 * Desired base address (or NULL) on entry;
3630 * Actual base address of the view on exit.
3633 * Number of high order address bits that must be zero.
3636 * Size in bytes of the initially committed section of
3640 * Offset in bytes from the beginning of the section
3641 * to the beginning of the view.
3644 * Desired length of map (or zero to map all) on entry
3645 * Actual length mapped on exit.
3647 * InheritDisposition
3648 * Specified how the view is to be shared with
3652 * Type of allocation for the pages.
3655 * Protection for the committed region of the view.
3663 NtMapViewOfSection(IN HANDLE SectionHandle
,
3664 IN HANDLE ProcessHandle
,
3665 IN OUT PVOID
* BaseAddress OPTIONAL
,
3666 IN ULONG ZeroBits OPTIONAL
,
3667 IN ULONG CommitSize
,
3668 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3669 IN OUT PSIZE_T ViewSize
,
3670 IN SECTION_INHERIT InheritDisposition
,
3671 IN ULONG AllocationType OPTIONAL
,
3674 PVOID SafeBaseAddress
;
3675 LARGE_INTEGER SafeSectionOffset
;
3676 SIZE_T SafeViewSize
;
3677 PROS_SECTION_OBJECT Section
;
3679 KPROCESSOR_MODE PreviousMode
;
3680 PMM_AVL_TABLE AddressSpace
;
3681 NTSTATUS Status
= STATUS_SUCCESS
;
3685 * Check the protection
3687 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3690 return STATUS_INVALID_PARAMETER_10
;
3693 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3694 if (tmpProtect
!= PAGE_NOACCESS
&&
3695 tmpProtect
!= PAGE_READONLY
&&
3696 tmpProtect
!= PAGE_READWRITE
&&
3697 tmpProtect
!= PAGE_WRITECOPY
&&
3698 tmpProtect
!= PAGE_EXECUTE
&&
3699 tmpProtect
!= PAGE_EXECUTE_READ
&&
3700 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3701 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3704 return STATUS_INVALID_PAGE_PROTECTION
;
3707 PreviousMode
= ExGetPreviousMode();
3709 if(PreviousMode
!= KernelMode
)
3711 SafeBaseAddress
= NULL
;
3712 SafeSectionOffset
.QuadPart
= 0;
3717 if(BaseAddress
!= NULL
)
3719 ProbeForWritePointer(BaseAddress
);
3720 SafeBaseAddress
= *BaseAddress
;
3722 if(SectionOffset
!= NULL
)
3724 ProbeForWriteLargeInteger(SectionOffset
);
3725 SafeSectionOffset
= *SectionOffset
;
3727 ProbeForWriteSize_t(ViewSize
);
3728 SafeViewSize
= *ViewSize
;
3732 Status
= _SEH_GetExceptionCode();
3736 if(!NT_SUCCESS(Status
))
3743 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3744 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3745 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3748 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3750 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3751 PROCESS_VM_OPERATION
,
3754 (PVOID
*)(PVOID
)&Process
,
3756 if (!NT_SUCCESS(Status
))
3761 AddressSpace
= &Process
->VadRoot
;
3763 Status
= ObReferenceObjectByHandle(SectionHandle
,
3765 MmSectionObjectType
,
3767 (PVOID
*)(PVOID
)&Section
,
3769 if (!(NT_SUCCESS(Status
)))
3771 DPRINT("ObReference failed rc=%x\n",Status
);
3772 ObDereferenceObject(Process
);
3776 Status
= MmMapViewOfSection(Section
,
3778 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3781 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3782 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3787 /* Check if this is an image for the current process */
3788 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3789 (Process
== PsGetCurrentProcess()) &&
3790 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3792 /* Notify the debugger */
3793 DbgkMapViewOfSection(Section
,
3795 SafeSectionOffset
.LowPart
,
3799 ObDereferenceObject(Section
);
3800 ObDereferenceObject(Process
);
3802 if(NT_SUCCESS(Status
))
3804 /* copy parameters back to the caller */
3807 if(BaseAddress
!= NULL
)
3809 *BaseAddress
= SafeBaseAddress
;
3811 if(SectionOffset
!= NULL
)
3813 *SectionOffset
= SafeSectionOffset
;
3815 if(ViewSize
!= NULL
)
3817 *ViewSize
= SafeViewSize
;
3822 Status
= _SEH_GetExceptionCode();
3831 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3832 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3835 PFILE_OBJECT FileObject
;
3838 SWAPENTRY SavedSwapEntry
;
3841 PROS_SECTION_OBJECT Section
;
3842 PMM_SECTION_SEGMENT Segment
;
3843 PMM_AVL_TABLE AddressSpace
;
3846 AddressSpace
= (PMM_AVL_TABLE
)Context
;
3847 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3849 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3851 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3852 MemoryArea
->Data
.SectionData
.ViewOffset
;
3854 Section
= MemoryArea
->Data
.SectionData
.Section
;
3855 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3857 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3861 MmUnlockSectionSegment(Segment
);
3862 MmUnlockAddressSpace(AddressSpace
);
3864 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3865 if (Status
!= STATUS_SUCCESS
)
3867 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3871 MmLockAddressSpace(AddressSpace
);
3872 MmLockSectionSegment(Segment
);
3873 MmspCompleteAndReleasePageOp(PageOp
);
3874 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3877 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3880 * For a dirty, datafile, non-private page mark it as dirty in the
3883 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3885 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3887 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3888 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3889 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3890 ASSERT(SwapEntry
== 0);
3899 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3901 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3904 MmFreeSwapPage(SwapEntry
);
3908 if (IS_SWAP_FROM_SSE(Entry
) ||
3909 Page
!= PFN_FROM_SSE(Entry
))
3914 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3916 DPRINT1("Found a private page in a pagefile section.\n");
3920 * Just dereference private pages
3922 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3923 if (SavedSwapEntry
!= 0)
3925 MmFreeSwapPage(SavedSwapEntry
);
3926 MmSetSavedSwapEntryPage(Page
, 0);
3928 MmDeleteRmap(Page
, Process
, Address
);
3929 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3933 MmDeleteRmap(Page
, Process
, Address
);
3934 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3940 MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3944 PMEMORY_AREA MemoryArea
;
3945 PROS_SECTION_OBJECT Section
;
3946 PMM_SECTION_SEGMENT Segment
;
3947 PLIST_ENTRY CurrentEntry
;
3948 PMM_REGION CurrentRegion
;
3949 PLIST_ENTRY RegionListHead
;
3951 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3953 if (MemoryArea
== NULL
)
3955 return(STATUS_UNSUCCESSFUL
);
3958 MemoryArea
->DeleteInProgress
= TRUE
;
3959 Section
= MemoryArea
->Data
.SectionData
.Section
;
3960 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3962 MmLockSectionSegment(Segment
);
3964 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3965 while (!IsListEmpty(RegionListHead
))
3967 CurrentEntry
= RemoveHeadList(RegionListHead
);
3968 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3969 ExFreePool(CurrentRegion
);
3972 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3974 Status
= MmFreeMemoryArea(AddressSpace
,
3981 Status
= MmFreeMemoryArea(AddressSpace
,
3986 MmUnlockSectionSegment(Segment
);
3987 ObDereferenceObject(Section
);
3988 return(STATUS_SUCCESS
);
3995 MmUnmapViewOfSection(PEPROCESS Process
,
3999 PMEMORY_AREA MemoryArea
;
4000 PMM_AVL_TABLE AddressSpace
;
4001 PROS_SECTION_OBJECT Section
;
4004 PVOID ImageBaseAddress
= 0;
4006 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4007 Process
, BaseAddress
);
4011 AddressSpace
= &Process
->VadRoot
;
4013 MmLockAddressSpace(AddressSpace
);
4014 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4016 if (MemoryArea
== NULL
||
4017 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4018 MemoryArea
->DeleteInProgress
)
4020 MmUnlockAddressSpace(AddressSpace
);
4021 return STATUS_NOT_MAPPED_VIEW
;
4024 MemoryArea
->DeleteInProgress
= TRUE
;
4026 while (MemoryArea
->PageOpCount
)
4028 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4032 Offset
-= PAGE_SIZE
;
4033 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4034 MemoryArea
->Data
.SectionData
.Segment
,
4035 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4038 MmUnlockAddressSpace(AddressSpace
);
4039 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4040 if (Status
!= STATUS_SUCCESS
)
4042 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4045 MmLockAddressSpace(AddressSpace
);
4046 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4048 if (MemoryArea
== NULL
||
4049 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4051 MmUnlockAddressSpace(AddressSpace
);
4052 return STATUS_NOT_MAPPED_VIEW
;
4059 Section
= MemoryArea
->Data
.SectionData
.Section
;
4061 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4065 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4066 PMM_SECTION_SEGMENT SectionSegments
;
4067 PMM_SECTION_SEGMENT Segment
;
4069 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4070 ImageSectionObject
= Section
->ImageSection
;
4071 SectionSegments
= ImageSectionObject
->Segments
;
4072 NrSegments
= ImageSectionObject
->NrSegments
;
4074 /* Search for the current segment within the section segments
4075 * and calculate the image base address */
4076 for (i
= 0; i
< NrSegments
; i
++)
4078 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4080 if (Segment
== &SectionSegments
[i
])
4082 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4087 if (i
>= NrSegments
)
4092 for (i
= 0; i
< NrSegments
; i
++)
4094 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4096 PVOID SBaseAddress
= (PVOID
)
4097 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4099 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4105 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4108 /* Notify debugger */
4109 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4111 MmUnlockAddressSpace(AddressSpace
);
4112 return(STATUS_SUCCESS
);
4115 /**********************************************************************
4117 * NtUnmapViewOfSection
4132 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4136 KPROCESSOR_MODE PreviousMode
;
4139 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4140 ProcessHandle
, BaseAddress
);
4142 PreviousMode
= ExGetPreviousMode();
4144 DPRINT("Referencing process\n");
4145 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4146 PROCESS_VM_OPERATION
,
4149 (PVOID
*)(PVOID
)&Process
,
4151 if (!NT_SUCCESS(Status
))
4153 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4157 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4159 ObDereferenceObject(Process
);
4166 * Queries the information of a section object.
4168 * @param SectionHandle
4169 * Handle to the section object. It must be opened with SECTION_QUERY
4171 * @param SectionInformationClass
4172 * Index to a certain information structure. Can be either
4173 * SectionBasicInformation or SectionImageInformation. The latter
4174 * is valid only for sections that were created with the SEC_IMAGE
4176 * @param SectionInformation
4177 * Caller supplies storage for resulting information.
4179 * Size of the supplied storage.
4180 * @param ResultLength
4188 NtQuerySection(IN HANDLE SectionHandle
,
4189 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4190 OUT PVOID SectionInformation
,
4191 IN ULONG SectionInformationLength
,
4192 OUT PULONG ResultLength OPTIONAL
)
4194 PROS_SECTION_OBJECT Section
;
4195 KPROCESSOR_MODE PreviousMode
;
4196 NTSTATUS Status
= STATUS_SUCCESS
;
4198 PreviousMode
= ExGetPreviousMode();
4200 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4202 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4204 SectionInformationLength
,
4208 if(!NT_SUCCESS(Status
))
4210 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4214 Status
= ObReferenceObjectByHandle(SectionHandle
,
4216 MmSectionObjectType
,
4218 (PVOID
*)(PVOID
)&Section
,
4220 if (NT_SUCCESS(Status
))
4222 switch (SectionInformationClass
)
4224 case SectionBasicInformation
:
4226 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4230 Sbi
->Attributes
= Section
->AllocationAttributes
;
4231 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4233 Sbi
->BaseAddress
= 0;
4234 Sbi
->Size
.QuadPart
= 0;
4238 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4239 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4242 if (ResultLength
!= NULL
)
4244 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4246 Status
= STATUS_SUCCESS
;
4250 Status
= _SEH_GetExceptionCode();
4257 case SectionImageInformation
:
4259 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4263 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4264 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4266 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4267 ImageSectionObject
= Section
->ImageSection
;
4269 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4270 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4271 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4272 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4273 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4274 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4275 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4276 Sii
->Machine
= ImageSectionObject
->Machine
;
4277 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4280 if (ResultLength
!= NULL
)
4282 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4284 Status
= STATUS_SUCCESS
;
4288 Status
= _SEH_GetExceptionCode();
4296 ObDereferenceObject(Section
);
4304 * Extends size of file backed section.
4306 * @param SectionHandle
4307 * Handle to the section object. It must be opened with
4308 * SECTION_EXTEND_SIZE access.
4309 * @param NewMaximumSize
4310 * New maximum size of the section in bytes.
4314 * @todo Move the actual code to internal function MmExtendSection.
4318 NtExtendSection(IN HANDLE SectionHandle
,
4319 IN PLARGE_INTEGER NewMaximumSize
)
4321 LARGE_INTEGER SafeNewMaximumSize
;
4322 PROS_SECTION_OBJECT Section
;
4323 KPROCESSOR_MODE PreviousMode
;
4324 NTSTATUS Status
= STATUS_SUCCESS
;
4326 PreviousMode
= ExGetPreviousMode();
4328 if(PreviousMode
!= KernelMode
)
4332 /* make a copy on the stack */
4333 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4334 NewMaximumSize
= &SafeNewMaximumSize
;
4338 Status
= _SEH_GetExceptionCode();
4342 if(!NT_SUCCESS(Status
))
4348 Status
= ObReferenceObjectByHandle(SectionHandle
,
4349 SECTION_EXTEND_SIZE
,
4350 MmSectionObjectType
,
4354 if (!NT_SUCCESS(Status
))
4359 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4361 ObfDereferenceObject(Section
);
4362 return STATUS_INVALID_PARAMETER
;
4366 * - Acquire file extneding resource.
4367 * - Check if we're not resizing the section below it's actual size!
4368 * - Extend segments if needed.
4369 * - Set file information (FileAllocationInformation) to the new size.
4370 * - Release file extending resource.
4373 ObDereferenceObject(Section
);
4375 return STATUS_NOT_IMPLEMENTED
;
4379 /**********************************************************************
4381 * MmAllocateSection@4
4391 * Code taken from ntoskrnl/mm/special.c.
4396 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4401 PMM_AVL_TABLE AddressSpace
;
4402 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4404 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4406 BoundaryAddressMultiple
.QuadPart
= 0;
4408 AddressSpace
= MmGetKernelAddressSpace();
4409 Result
= BaseAddress
;
4410 MmLockAddressSpace(AddressSpace
);
4411 Status
= MmCreateMemoryArea (AddressSpace
,
4419 BoundaryAddressMultiple
);
4420 MmUnlockAddressSpace(AddressSpace
);
4422 if (!NT_SUCCESS(Status
))
4426 DPRINT("Result %p\n",Result
);
4428 /* Create a virtual mapping for this memory area */
4429 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4431 return ((PVOID
)Result
);
4435 /**********************************************************************
4437 * MmMapViewOfSection
4440 * Maps a view of a section into the virtual address space of a
4445 * Pointer to the section object.
4448 * Pointer to the process.
4451 * Desired base address (or NULL) on entry;
4452 * Actual base address of the view on exit.
4455 * Number of high order address bits that must be zero.
4458 * Size in bytes of the initially committed section of
4462 * Offset in bytes from the beginning of the section
4463 * to the beginning of the view.
4466 * Desired length of map (or zero to map all) on entry
4467 * Actual length mapped on exit.
4469 * InheritDisposition
4470 * Specified how the view is to be shared with
4474 * Type of allocation for the pages.
4477 * Protection for the committed region of the view.
4485 MmMapViewOfSection(IN PVOID SectionObject
,
4486 IN PEPROCESS Process
,
4487 IN OUT PVOID
*BaseAddress
,
4489 IN ULONG CommitSize
,
4490 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4491 IN OUT PSIZE_T ViewSize
,
4492 IN SECTION_INHERIT InheritDisposition
,
4493 IN ULONG AllocationType
,
4496 PROS_SECTION_OBJECT Section
;
4497 PMM_AVL_TABLE AddressSpace
;
4499 NTSTATUS Status
= STATUS_SUCCESS
;
4503 if (Protect
!= PAGE_READONLY
&&
4504 Protect
!= PAGE_READWRITE
&&
4505 Protect
!= PAGE_WRITECOPY
&&
4506 Protect
!= PAGE_EXECUTE
&&
4507 Protect
!= PAGE_EXECUTE_READ
&&
4508 Protect
!= PAGE_EXECUTE_READWRITE
&&
4509 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4512 return STATUS_INVALID_PAGE_PROTECTION
;
4516 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4517 AddressSpace
= &Process
->VadRoot
;
4519 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4521 MmLockAddressSpace(AddressSpace
);
4523 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4527 ULONG_PTR ImageBase
;
4529 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4530 PMM_SECTION_SEGMENT SectionSegments
;
4532 ImageSectionObject
= Section
->ImageSection
;
4533 SectionSegments
= ImageSectionObject
->Segments
;
4534 NrSegments
= ImageSectionObject
->NrSegments
;
4537 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4540 ImageBase
= ImageSectionObject
->ImageBase
;
4544 for (i
= 0; i
< NrSegments
; i
++)
4546 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4548 ULONG_PTR MaxExtent
;
4549 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4550 SectionSegments
[i
].Length
;
4551 ImageSize
= max(ImageSize
, MaxExtent
);
4555 ImageSectionObject
->ImageSize
= ImageSize
;
4557 /* Check there is enough space to map the section at that point. */
4558 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4559 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4561 /* Fail if the user requested a fixed base address. */
4562 if ((*BaseAddress
) != NULL
)
4564 MmUnlockAddressSpace(AddressSpace
);
4565 return(STATUS_UNSUCCESSFUL
);
4567 /* Otherwise find a gap to map the image. */
4568 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4571 MmUnlockAddressSpace(AddressSpace
);
4572 return(STATUS_UNSUCCESSFUL
);
4576 for (i
= 0; i
< NrSegments
; i
++)
4578 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4580 PVOID SBaseAddress
= (PVOID
)
4581 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4582 MmLockSectionSegment(&SectionSegments
[i
]);
4583 Status
= MmMapViewOfSegment(AddressSpace
,
4585 &SectionSegments
[i
],
4587 SectionSegments
[i
].Length
,
4588 SectionSegments
[i
].Protection
,
4591 MmUnlockSectionSegment(&SectionSegments
[i
]);
4592 if (!NT_SUCCESS(Status
))
4594 MmUnlockAddressSpace(AddressSpace
);
4600 *BaseAddress
= (PVOID
)ImageBase
;
4604 /* check for write access */
4605 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4606 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4609 return STATUS_SECTION_PROTECTION
;
4611 /* check for read access */
4612 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4613 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4616 return STATUS_SECTION_PROTECTION
;
4618 /* check for execute access */
4619 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4620 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4623 return STATUS_SECTION_PROTECTION
;
4626 if (ViewSize
== NULL
)
4628 /* Following this pointer would lead to us to the dark side */
4629 /* What to do? Bugcheck? Return status? Do the mambo? */
4630 KEBUGCHECK(MEMORY_MANAGEMENT
);
4633 if (SectionOffset
== NULL
)
4639 ViewOffset
= SectionOffset
->u
.LowPart
;
4642 if ((ViewOffset
% PAGE_SIZE
) != 0)
4644 MmUnlockAddressSpace(AddressSpace
);
4645 return(STATUS_MAPPED_ALIGNMENT
);
4648 if ((*ViewSize
) == 0)
4650 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4652 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4654 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4657 MmLockSectionSegment(Section
->Segment
);
4658 Status
= MmMapViewOfSegment(AddressSpace
,
4665 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4666 MmUnlockSectionSegment(Section
->Segment
);
4667 if (!NT_SUCCESS(Status
))
4669 MmUnlockAddressSpace(AddressSpace
);
4674 MmUnlockAddressSpace(AddressSpace
);
4676 return(STATUS_SUCCESS
);
4683 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4684 IN PLARGE_INTEGER NewFileSize
)
4695 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4705 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4706 IN MMFLUSH_TYPE FlushType
)
4710 case MmFlushForDelete
:
4711 if (SectionObjectPointer
->ImageSectionObject
||
4712 SectionObjectPointer
->DataSectionObject
)
4716 CcRosSetRemoveOnClose(SectionObjectPointer
);
4718 case MmFlushForWrite
:
4728 MmForceSectionClosed (
4729 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4730 IN BOOLEAN DelayClose
)
4741 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4742 OUT PVOID
* MappedBase
,
4743 IN OUT PULONG ViewSize
)
4745 PROS_SECTION_OBJECT Section
;
4746 PMM_AVL_TABLE AddressSpace
;
4749 DPRINT("MmMapViewInSystemSpace() called\n");
4751 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4752 AddressSpace
= MmGetKernelAddressSpace();
4754 MmLockAddressSpace(AddressSpace
);
4757 if ((*ViewSize
) == 0)
4759 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4761 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4763 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4766 MmLockSectionSegment(Section
->Segment
);
4769 Status
= MmMapViewOfSegment(AddressSpace
,
4778 MmUnlockSectionSegment(Section
->Segment
);
4779 MmUnlockAddressSpace(AddressSpace
);
4789 MmMapViewInSessionSpace (
4791 OUT PVOID
*MappedBase
,
4792 IN OUT PSIZE_T ViewSize
4796 return STATUS_NOT_IMPLEMENTED
;
4804 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4806 PMM_AVL_TABLE AddressSpace
;
4809 DPRINT("MmUnmapViewInSystemSpace() called\n");
4811 AddressSpace
= MmGetKernelAddressSpace();
4813 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4823 MmUnmapViewInSessionSpace (
4828 return STATUS_NOT_IMPLEMENTED
;
4835 MmSetBankedSection (ULONG Unknown0
,
4843 return (STATUS_NOT_IMPLEMENTED
);
4847 /**********************************************************************
4852 * Creates a section object.
4855 * SectionObject (OUT)
4856 * Caller supplied storage for the resulting pointer
4857 * to a SECTION_OBJECT instance;
4860 * Specifies the desired access to the section can be a
4862 * STANDARD_RIGHTS_REQUIRED |
4864 * SECTION_MAP_WRITE |
4865 * SECTION_MAP_READ |
4866 * SECTION_MAP_EXECUTE
4868 * ObjectAttributes [OPTIONAL]
4869 * Initialized attributes for the object can be used
4870 * to create a named section;
4873 * Maximizes the size of the memory section. Must be
4874 * non-NULL for a page-file backed section.
4875 * If value specified for a mapped file and the file is
4876 * not large enough, file will be extended.
4878 * SectionPageProtection
4879 * Can be a combination of:
4885 * AllocationAttributes
4886 * Can be a combination of:
4891 * Handle to a file to create a section mapped to a file
4892 * instead of a memory backed section;
4903 MmCreateSection (OUT PVOID
* Section
,
4904 IN ACCESS_MASK DesiredAccess
,
4905 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4906 IN PLARGE_INTEGER MaximumSize
,
4907 IN ULONG SectionPageProtection
,
4908 IN ULONG AllocationAttributes
,
4909 IN HANDLE FileHandle OPTIONAL
,
4910 IN PFILE_OBJECT File OPTIONAL
)
4913 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4916 * Check the protection
4918 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4919 if (Protection
!= PAGE_NOACCESS
&&
4920 Protection
!= PAGE_READONLY
&&
4921 Protection
!= PAGE_READWRITE
&&
4922 Protection
!= PAGE_WRITECOPY
&&
4923 Protection
!= PAGE_EXECUTE
&&
4924 Protection
!= PAGE_EXECUTE_READ
&&
4925 Protection
!= PAGE_EXECUTE_READWRITE
&&
4926 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4929 return STATUS_INVALID_PAGE_PROTECTION
;
4932 if (AllocationAttributes
& SEC_IMAGE
)
4934 return(MmCreateImageSection(SectionObject
,
4938 SectionPageProtection
,
4939 AllocationAttributes
,
4943 if (FileHandle
!= NULL
)
4945 return(MmCreateDataFileSection(SectionObject
,
4949 SectionPageProtection
,
4950 AllocationAttributes
,
4954 return(MmCreatePageFileSection(SectionObject
,
4958 SectionPageProtection
,
4959 AllocationAttributes
));
4964 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
4965 IN OUT PULONG NumberOfPages
,
4966 IN OUT PULONG UserPfnArray
)
4969 return STATUS_NOT_IMPLEMENTED
;
4974 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
4975 IN ULONG NumberOfPages
,
4976 IN OUT PULONG UserPfnArray
)
4979 return STATUS_NOT_IMPLEMENTED
;
4984 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
4985 IN ULONG NumberOfPages
,
4986 IN OUT PULONG UserPfnArray
)
4989 return STATUS_NOT_IMPLEMENTED
;
4994 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
4995 IN OUT PULONG NumberOfPages
,
4996 IN OUT PULONG UserPfnArray
)
4999 return STATUS_NOT_IMPLEMENTED
;
5004 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5005 IN PVOID File2MappedAsFile
)
5008 return STATUS_NOT_IMPLEMENTED
;