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 MADDRESS_SPACE 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(PMADDRESS_SPACE AddressSpace
,
711 MEMORY_AREA
* MemoryArea
,
719 PROS_SECTION_OBJECT Section
;
720 PMM_SECTION_SEGMENT Segment
;
726 BOOLEAN HasSwapEntry
;
729 * There is a window between taking the page fault and locking the
730 * address space when another thread could load the page so we check
733 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
737 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
739 return(STATUS_SUCCESS
);
742 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
743 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
744 + MemoryArea
->Data
.SectionData
.ViewOffset
;
746 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
747 Section
= MemoryArea
->Data
.SectionData
.Section
;
748 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
749 &MemoryArea
->Data
.SectionData
.RegionListHead
,
754 MmLockSectionSegment(Segment
);
757 * Check if this page needs to be mapped COW
759 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
760 (Region
->Protect
== PAGE_READWRITE
||
761 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
763 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
767 Attributes
= Region
->Protect
;
771 * Get or create a page operation descriptor
773 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
776 DPRINT1("MmGetPageOp failed\n");
781 * Check if someone else is already handling this fault, if so wait
784 if (PageOp
->Thread
!= PsGetCurrentThread())
786 MmUnlockSectionSegment(Segment
);
787 MmUnlockAddressSpace(AddressSpace
);
788 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
790 * Check for various strange conditions
792 if (Status
!= STATUS_SUCCESS
)
794 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
797 if (PageOp
->Status
== STATUS_PENDING
)
799 DPRINT1("Woke for page op before completion\n");
802 MmLockAddressSpace(AddressSpace
);
804 * If this wasn't a pagein then restart the operation
806 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
808 MmspCompleteAndReleasePageOp(PageOp
);
809 DPRINT("Address 0x%.8X\n", Address
);
810 return(STATUS_MM_RESTART_OPERATION
);
814 * If the thread handling this fault has failed then we don't retry
816 if (!NT_SUCCESS(PageOp
->Status
))
818 Status
= PageOp
->Status
;
819 MmspCompleteAndReleasePageOp(PageOp
);
820 DPRINT("Address 0x%.8X\n", Address
);
823 MmLockSectionSegment(Segment
);
825 * If the completed fault was for another address space then set the
828 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
830 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
831 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
833 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
836 * The page was a private page in another or in our address space
838 MmUnlockSectionSegment(Segment
);
839 MmspCompleteAndReleasePageOp(PageOp
);
840 return(STATUS_MM_RESTART_OPERATION
);
843 Page
= PFN_FROM_SSE(Entry
);
845 MmSharePageEntrySectionSegment(Segment
, Offset
);
847 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
848 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
850 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
855 if (!NT_SUCCESS(Status
))
857 DPRINT1("Unable to create virtual mapping\n");
860 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
866 MmUnlockSectionSegment(Segment
);
867 PageOp
->Status
= STATUS_SUCCESS
;
868 MmspCompleteAndReleasePageOp(PageOp
);
869 DPRINT("Address 0x%.8X\n", Address
);
870 return(STATUS_SUCCESS
);
873 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
877 * Must be private page we have swapped out.
884 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
886 DPRINT1("Found a swaped out private page in a pagefile section.\n");
890 MmUnlockSectionSegment(Segment
);
891 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
893 MmUnlockAddressSpace(AddressSpace
);
894 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
895 if (!NT_SUCCESS(Status
))
900 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
901 if (!NT_SUCCESS(Status
))
903 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
906 MmLockAddressSpace(AddressSpace
);
907 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
912 if (!NT_SUCCESS(Status
))
914 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
920 * Store the swap entry for later use.
922 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
925 * Add the page to the process's working set
927 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
930 * Finish the operation
936 PageOp
->Status
= STATUS_SUCCESS
;
937 MmspCompleteAndReleasePageOp(PageOp
);
938 DPRINT("Address 0x%.8X\n", Address
);
939 return(STATUS_SUCCESS
);
943 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
945 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
947 MmUnlockSectionSegment(Segment
);
949 * Just map the desired physical page
951 Page
= Offset
>> PAGE_SHIFT
;
952 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
957 if (!NT_SUCCESS(Status
))
959 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
964 * Don't add an rmap entry since the page mapped could be for
969 MmLockPageUnsafe(Page
);
973 * Cleanup and release locks
975 PageOp
->Status
= STATUS_SUCCESS
;
976 MmspCompleteAndReleasePageOp(PageOp
);
977 DPRINT("Address 0x%.8X\n", Address
);
978 return(STATUS_SUCCESS
);
982 * Map anonymous memory for BSS sections
984 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
986 MmUnlockSectionSegment(Segment
);
987 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
988 if (!NT_SUCCESS(Status
))
990 MmUnlockAddressSpace(AddressSpace
);
991 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
992 MmLockAddressSpace(AddressSpace
);
994 if (!NT_SUCCESS(Status
))
998 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1003 if (!NT_SUCCESS(Status
))
1005 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1009 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1016 * Cleanup and release locks
1018 PageOp
->Status
= STATUS_SUCCESS
;
1019 MmspCompleteAndReleasePageOp(PageOp
);
1020 DPRINT("Address 0x%.8X\n", Address
);
1021 return(STATUS_SUCCESS
);
1025 * Get the entry corresponding to the offset within the section
1027 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1032 * If the entry is zero (and it can't change because we have
1033 * locked the segment) then we need to load the page.
1037 * Release all our locks and read in the page from disk
1039 MmUnlockSectionSegment(Segment
);
1040 MmUnlockAddressSpace(AddressSpace
);
1042 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1043 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1045 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1046 if (!NT_SUCCESS(Status
))
1048 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1053 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1054 if (!NT_SUCCESS(Status
))
1056 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1059 if (!NT_SUCCESS(Status
))
1062 * FIXME: What do we know in this case?
1065 * Cleanup and release locks
1067 MmLockAddressSpace(AddressSpace
);
1068 PageOp
->Status
= Status
;
1069 MmspCompleteAndReleasePageOp(PageOp
);
1070 DPRINT("Address 0x%.8X\n", Address
);
1074 * Relock the address space and segment
1076 MmLockAddressSpace(AddressSpace
);
1077 MmLockSectionSegment(Segment
);
1080 * Check the entry. No one should change the status of a page
1081 * that has a pending page-in.
1083 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1084 if (Entry
!= Entry1
)
1086 DPRINT1("Someone changed ppte entry while we slept\n");
1091 * Mark the offset within the section as having valid, in-memory
1094 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1095 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1096 MmUnlockSectionSegment(Segment
);
1098 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1103 if (!NT_SUCCESS(Status
))
1105 DPRINT1("Unable to create virtual mapping\n");
1108 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1114 PageOp
->Status
= STATUS_SUCCESS
;
1115 MmspCompleteAndReleasePageOp(PageOp
);
1116 DPRINT("Address 0x%.8X\n", Address
);
1117 return(STATUS_SUCCESS
);
1119 else if (IS_SWAP_FROM_SSE(Entry
))
1121 SWAPENTRY SwapEntry
;
1123 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1126 * Release all our locks and read in the page from disk
1128 MmUnlockSectionSegment(Segment
);
1130 MmUnlockAddressSpace(AddressSpace
);
1132 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1133 if (!NT_SUCCESS(Status
))
1138 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1139 if (!NT_SUCCESS(Status
))
1145 * Relock the address space and segment
1147 MmLockAddressSpace(AddressSpace
);
1148 MmLockSectionSegment(Segment
);
1151 * Check the entry. No one should change the status of a page
1152 * that has a pending page-in.
1154 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1155 if (Entry
!= Entry1
)
1157 DPRINT1("Someone changed ppte entry while we slept\n");
1162 * Mark the offset within the section as having valid, in-memory
1165 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1166 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1167 MmUnlockSectionSegment(Segment
);
1170 * Save the swap entry.
1172 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1173 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1178 if (!NT_SUCCESS(Status
))
1180 DPRINT1("Unable to create virtual mapping\n");
1183 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1188 PageOp
->Status
= STATUS_SUCCESS
;
1189 MmspCompleteAndReleasePageOp(PageOp
);
1190 DPRINT("Address 0x%.8X\n", Address
);
1191 return(STATUS_SUCCESS
);
1196 * If the section offset is already in-memory and valid then just
1197 * take another reference to the page
1200 Page
= PFN_FROM_SSE(Entry
);
1202 MmSharePageEntrySectionSegment(Segment
, Offset
);
1203 MmUnlockSectionSegment(Segment
);
1205 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1210 if (!NT_SUCCESS(Status
))
1212 DPRINT1("Unable to create virtual mapping\n");
1215 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1220 PageOp
->Status
= STATUS_SUCCESS
;
1221 MmspCompleteAndReleasePageOp(PageOp
);
1222 DPRINT("Address 0x%.8X\n", Address
);
1223 return(STATUS_SUCCESS
);
1229 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1230 MEMORY_AREA
* MemoryArea
,
1234 PMM_SECTION_SEGMENT Segment
;
1235 PROS_SECTION_OBJECT Section
;
1245 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1248 * Check if the page has been paged out or has already been set readwrite
1250 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1251 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1253 DPRINT("Address 0x%.8X\n", Address
);
1254 return(STATUS_SUCCESS
);
1258 * Find the offset of the page
1260 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1261 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1262 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1264 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1265 Section
= MemoryArea
->Data
.SectionData
.Section
;
1266 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1267 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1272 MmLockSectionSegment(Segment
);
1274 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1275 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1277 MmUnlockSectionSegment(Segment
);
1280 * Check if we are doing COW
1282 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1283 (Region
->Protect
== PAGE_READWRITE
||
1284 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1286 DPRINT("Address 0x%.8X\n", Address
);
1287 return(STATUS_UNSUCCESSFUL
);
1290 if (IS_SWAP_FROM_SSE(Entry
) ||
1291 PFN_FROM_SSE(Entry
) != OldPage
)
1293 /* This is a private page. We must only change the page protection. */
1294 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1295 return(STATUS_SUCCESS
);
1299 * Get or create a pageop
1301 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1302 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1305 DPRINT1("MmGetPageOp failed\n");
1310 * Wait for any other operations to complete
1312 if (PageOp
->Thread
!= PsGetCurrentThread())
1314 MmUnlockAddressSpace(AddressSpace
);
1315 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1317 * Check for various strange conditions
1319 if (Status
== STATUS_TIMEOUT
)
1321 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1324 if (PageOp
->Status
== STATUS_PENDING
)
1326 DPRINT1("Woke for page op before completion\n");
1330 * Restart the operation
1332 MmLockAddressSpace(AddressSpace
);
1333 MmspCompleteAndReleasePageOp(PageOp
);
1334 DPRINT("Address 0x%.8X\n", Address
);
1335 return(STATUS_MM_RESTART_OPERATION
);
1339 * Release locks now we have the pageop
1341 MmUnlockAddressSpace(AddressSpace
);
1346 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1347 if (!NT_SUCCESS(Status
))
1355 MiCopyFromUserPage(NewPage
, PAddress
);
1357 MmLockAddressSpace(AddressSpace
);
1359 * Delete the old entry.
1361 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1364 * Set the PTE to point to the new page
1366 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1371 if (!NT_SUCCESS(Status
))
1373 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1377 if (!NT_SUCCESS(Status
))
1379 DPRINT1("Unable to create virtual mapping\n");
1384 MmLockPage(NewPage
);
1385 MmUnlockPage(OldPage
);
1389 * Unshare the old page.
1391 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1392 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1393 MmLockSectionSegment(Segment
);
1394 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1395 MmUnlockSectionSegment(Segment
);
1397 PageOp
->Status
= STATUS_SUCCESS
;
1398 MmspCompleteAndReleasePageOp(PageOp
);
1399 DPRINT("Address 0x%.8X\n", Address
);
1400 return(STATUS_SUCCESS
);
1404 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1406 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1410 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1413 MmLockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
1416 MmDeleteVirtualMapping(Process
,
1423 PageOutContext
->WasDirty
= TRUE
;
1425 if (!PageOutContext
->Private
)
1427 MmLockSectionSegment(PageOutContext
->Segment
);
1428 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1429 PageOutContext
->Segment
,
1430 PageOutContext
->Offset
,
1431 PageOutContext
->WasDirty
,
1433 MmUnlockSectionSegment(PageOutContext
->Segment
);
1437 MmUnlockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
1440 if (PageOutContext
->Private
)
1442 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1445 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1450 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1451 MEMORY_AREA
* MemoryArea
,
1456 MM_SECTION_PAGEOUT_CONTEXT Context
;
1457 SWAPENTRY SwapEntry
;
1461 PFILE_OBJECT FileObject
;
1463 BOOLEAN DirectMapped
;
1464 BOOLEAN IsImageSection
;
1466 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1469 * Get the segment and section.
1471 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1472 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1474 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1475 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1476 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1478 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1480 FileObject
= Context
.Section
->FileObject
;
1481 DirectMapped
= FALSE
;
1482 if (FileObject
!= NULL
&&
1483 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1485 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1488 * If the file system is letting us go directly to the cache and the
1489 * memory area was mapped at an offset in the file which is page aligned
1490 * then note this is a direct mapped page.
1492 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1493 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1495 DirectMapped
= TRUE
;
1501 * This should never happen since mappings of physical memory are never
1502 * placed in the rmap lists.
1504 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1506 DPRINT1("Trying to page out from physical memory section address 0x%X "
1507 "process %d\n", Address
,
1508 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1513 * Get the section segment entry and the physical address.
1515 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1516 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1518 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1519 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1522 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1523 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1526 * Prepare the context structure for the rmap delete call.
1528 Context
.WasDirty
= FALSE
;
1529 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1530 IS_SWAP_FROM_SSE(Entry
) ||
1531 PFN_FROM_SSE(Entry
) != Page
)
1533 Context
.Private
= TRUE
;
1537 Context
.Private
= FALSE
;
1541 * Take an additional reference to the page or the cache segment.
1543 if (DirectMapped
&& !Context
.Private
)
1545 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1547 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1553 MmReferencePage(Page
);
1556 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1559 * If this wasn't a private page then we should have reduced the entry to
1560 * zero by deleting all the rmaps.
1562 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1564 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1565 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1572 * If the page wasn't dirty then we can just free it as for a readonly page.
1573 * Since we unmapped all the mappings above we know it will not suddenly
1575 * If the page is from a pagefile section and has no swap entry,
1576 * we can't free the page at this point.
1578 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1579 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1581 if (Context
.Private
)
1583 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1584 Context
.WasDirty
? "dirty" : "clean", Address
);
1587 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1589 MmSetSavedSwapEntryPage(Page
, 0);
1590 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1591 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1592 PageOp
->Status
= STATUS_SUCCESS
;
1593 MmspCompleteAndReleasePageOp(PageOp
);
1594 return(STATUS_SUCCESS
);
1597 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1599 if (Context
.Private
)
1601 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1602 Context
.WasDirty
? "dirty" : "clean", Address
);
1605 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1607 MmSetSavedSwapEntryPage(Page
, 0);
1610 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1612 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1613 PageOp
->Status
= STATUS_SUCCESS
;
1614 MmspCompleteAndReleasePageOp(PageOp
);
1615 return(STATUS_SUCCESS
);
1618 else if (!Context
.Private
&& DirectMapped
)
1622 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1626 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1627 if (!NT_SUCCESS(Status
))
1629 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1632 PageOp
->Status
= STATUS_SUCCESS
;
1633 MmspCompleteAndReleasePageOp(PageOp
);
1634 return(STATUS_SUCCESS
);
1636 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1640 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1644 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1645 PageOp
->Status
= STATUS_SUCCESS
;
1646 MmspCompleteAndReleasePageOp(PageOp
);
1647 return(STATUS_SUCCESS
);
1649 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1651 MmSetSavedSwapEntryPage(Page
, 0);
1652 MmLockAddressSpace(AddressSpace
);
1653 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1656 MmUnlockAddressSpace(AddressSpace
);
1657 if (!NT_SUCCESS(Status
))
1661 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1662 PageOp
->Status
= STATUS_SUCCESS
;
1663 MmspCompleteAndReleasePageOp(PageOp
);
1664 return(STATUS_SUCCESS
);
1668 * If necessary, allocate an entry in the paging file for this page
1672 SwapEntry
= MmAllocSwapPage();
1675 MmShowOutOfSpaceMessagePagingFile();
1676 MmLockAddressSpace(AddressSpace
);
1678 * For private pages restore the old mappings.
1680 if (Context
.Private
)
1682 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1684 MemoryArea
->Protect
,
1687 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1689 AddressSpace
->Process
,
1695 * For non-private pages if the page wasn't direct mapped then
1696 * set it back into the section segment entry so we don't loose
1697 * our copy. Otherwise it will be handled by the cache manager.
1699 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1701 MemoryArea
->Protect
,
1704 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1706 AddressSpace
->Process
,
1708 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1709 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1711 MmUnlockAddressSpace(AddressSpace
);
1712 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1713 MmspCompleteAndReleasePageOp(PageOp
);
1714 return(STATUS_PAGEFILE_QUOTA
);
1719 * Write the page to the pagefile
1721 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1722 if (!NT_SUCCESS(Status
))
1724 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1727 * As above: undo our actions.
1728 * FIXME: Also free the swap page.
1730 MmLockAddressSpace(AddressSpace
);
1731 if (Context
.Private
)
1733 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1735 MemoryArea
->Protect
,
1738 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1740 AddressSpace
->Process
,
1745 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1747 MemoryArea
->Protect
,
1750 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1752 AddressSpace
->Process
,
1754 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1755 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1757 MmUnlockAddressSpace(AddressSpace
);
1758 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1759 MmspCompleteAndReleasePageOp(PageOp
);
1760 return(STATUS_UNSUCCESSFUL
);
1764 * Otherwise we have succeeded.
1766 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1767 MmSetSavedSwapEntryPage(Page
, 0);
1768 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1769 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1771 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1775 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1778 if (Context
.Private
)
1780 MmLockAddressSpace(AddressSpace
);
1781 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1784 MmUnlockAddressSpace(AddressSpace
);
1785 if (!NT_SUCCESS(Status
))
1792 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1793 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1796 PageOp
->Status
= STATUS_SUCCESS
;
1797 MmspCompleteAndReleasePageOp(PageOp
);
1798 return(STATUS_SUCCESS
);
1803 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1804 PMEMORY_AREA MemoryArea
,
1809 PROS_SECTION_OBJECT Section
;
1810 PMM_SECTION_SEGMENT Segment
;
1812 SWAPENTRY SwapEntry
;
1816 PFILE_OBJECT FileObject
;
1818 BOOLEAN DirectMapped
;
1819 BOOLEAN IsImageSection
;
1821 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1823 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1824 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1827 * Get the segment and section.
1829 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1830 Section
= MemoryArea
->Data
.SectionData
.Section
;
1831 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1833 FileObject
= Section
->FileObject
;
1834 DirectMapped
= FALSE
;
1835 if (FileObject
!= NULL
&&
1836 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1838 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1841 * If the file system is letting us go directly to the cache and the
1842 * memory area was mapped at an offset in the file which is page aligned
1843 * then note this is a direct mapped page.
1845 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1846 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1848 DirectMapped
= TRUE
;
1853 * This should never happen since mappings of physical memory are never
1854 * placed in the rmap lists.
1856 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1858 DPRINT1("Trying to write back page from physical memory mapped at %X "
1859 "process %d\n", Address
,
1860 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1865 * Get the section segment entry and the physical address.
1867 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1868 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1870 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1871 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1874 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1875 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1878 * Check for a private (COWed) page.
1880 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1881 IS_SWAP_FROM_SSE(Entry
) ||
1882 PFN_FROM_SSE(Entry
) != Page
)
1892 * Speculatively set all mappings of the page to clean.
1894 MmSetCleanAllRmaps(Page
);
1897 * If this page was direct mapped from the cache then the cache manager
1898 * will take care of writing it back to disk.
1900 if (DirectMapped
&& !Private
)
1902 ASSERT(SwapEntry
== 0);
1903 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1904 PageOp
->Status
= STATUS_SUCCESS
;
1905 MmspCompleteAndReleasePageOp(PageOp
);
1906 return(STATUS_SUCCESS
);
1910 * If necessary, allocate an entry in the paging file for this page
1914 SwapEntry
= MmAllocSwapPage();
1917 MmSetDirtyAllRmaps(Page
);
1918 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1919 MmspCompleteAndReleasePageOp(PageOp
);
1920 return(STATUS_PAGEFILE_QUOTA
);
1922 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1926 * Write the page to the pagefile
1928 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1929 if (!NT_SUCCESS(Status
))
1931 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1933 MmSetDirtyAllRmaps(Page
);
1934 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1935 MmspCompleteAndReleasePageOp(PageOp
);
1936 return(STATUS_UNSUCCESSFUL
);
1940 * Otherwise we have succeeded.
1942 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1943 PageOp
->Status
= STATUS_SUCCESS
;
1944 MmspCompleteAndReleasePageOp(PageOp
);
1945 return(STATUS_SUCCESS
);
1949 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1957 PMEMORY_AREA MemoryArea
;
1958 PMM_SECTION_SEGMENT Segment
;
1959 BOOLEAN DoCOW
= FALSE
;
1962 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1963 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1965 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1966 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1971 if (OldProtect
!= NewProtect
)
1973 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1975 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1976 ULONG Protect
= NewProtect
;
1979 * If we doing COW for this segment then check if the page is
1982 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1988 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1989 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1990 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1991 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1993 Protect
= PAGE_READONLY
;
1994 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1995 IS_SWAP_FROM_SSE(Entry
) ||
1996 PFN_FROM_SSE(Entry
) != Page
)
1998 Protect
= NewProtect
;
2002 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
2004 MmSetPageProtect(AddressSpace
->Process
, Address
,
2013 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
2014 PMEMORY_AREA MemoryArea
,
2022 ULONG_PTR MaxLength
;
2024 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2025 if (Length
> MaxLength
)
2028 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2029 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2031 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2032 Region
->Protect
!= Protect
)
2035 return STATUS_INVALID_PAGE_PROTECTION
;
2038 *OldProtect
= Region
->Protect
;
2039 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2040 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2041 BaseAddress
, Length
, Region
->Type
, Protect
,
2042 MmAlterViewAttributes
);
2048 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2050 PMEMORY_BASIC_INFORMATION Info
,
2051 PULONG ResultLength
)
2054 PVOID RegionBaseAddress
;
2055 PROS_SECTION_OBJECT Section
;
2056 PMM_SECTION_SEGMENT Segment
;
2058 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2059 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2060 Address
, &RegionBaseAddress
);
2063 return STATUS_UNSUCCESSFUL
;
2066 Section
= MemoryArea
->Data
.SectionData
.Section
;
2067 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2069 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2070 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2071 Info
->Type
= MEM_IMAGE
;
2075 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2076 Info
->Type
= MEM_MAPPED
;
2078 Info
->BaseAddress
= RegionBaseAddress
;
2079 Info
->AllocationProtect
= MemoryArea
->Protect
;
2080 Info
->RegionSize
= Region
->Length
;
2081 Info
->State
= MEM_COMMIT
;
2082 Info
->Protect
= Region
->Protect
;
2084 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2085 return(STATUS_SUCCESS
);
2090 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2095 ULONG SavedSwapEntry
;
2100 Length
= PAGE_ROUND_UP(Segment
->Length
);
2101 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2103 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2106 if (IS_SWAP_FROM_SSE(Entry
))
2108 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2112 Page
= PFN_FROM_SSE(Entry
);
2113 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2114 if (SavedSwapEntry
!= 0)
2116 MmSetSavedSwapEntryPage(Page
, 0);
2117 MmFreeSwapPage(SavedSwapEntry
);
2119 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2121 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2127 MmpDeleteSection(PVOID ObjectBody
)
2129 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2131 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2132 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2137 PMM_SECTION_SEGMENT SectionSegments
;
2140 * NOTE: Section->ImageSection can be NULL for short time
2141 * during the section creating. If we fail for some reason
2142 * until the image section is properly initialized we shouldn't
2143 * process further here.
2145 if (Section
->ImageSection
== NULL
)
2148 SectionSegments
= Section
->ImageSection
->Segments
;
2149 NrSegments
= Section
->ImageSection
->NrSegments
;
2151 for (i
= 0; i
< NrSegments
; i
++)
2153 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2155 MmLockSectionSegment(&SectionSegments
[i
]);
2157 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2158 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2162 MmpFreePageFileSegment(&SectionSegments
[i
]);
2164 MmUnlockSectionSegment(&SectionSegments
[i
]);
2171 * NOTE: Section->Segment can be NULL for short time
2172 * during the section creating.
2174 if (Section
->Segment
== NULL
)
2177 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2179 MmpFreePageFileSegment(Section
->Segment
);
2180 MmFreePageTablesSectionSegment(Section
->Segment
);
2181 ExFreePool(Section
->Segment
);
2182 Section
->Segment
= NULL
;
2186 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2189 if (Section
->FileObject
!= NULL
)
2191 CcRosDereferenceCache(Section
->FileObject
);
2192 ObDereferenceObject(Section
->FileObject
);
2193 Section
->FileObject
= NULL
;
2198 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2200 IN ACCESS_MASK GrantedAccess
,
2201 IN ULONG ProcessHandleCount
,
2202 IN ULONG SystemHandleCount
)
2204 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2205 Object
, ProcessHandleCount
);
2211 MmCreatePhysicalMemorySection(VOID
)
2213 PROS_SECTION_OBJECT PhysSection
;
2215 OBJECT_ATTRIBUTES Obj
;
2216 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2217 LARGE_INTEGER SectionSize
;
2221 * Create the section mapping physical memory
2223 SectionSize
.QuadPart
= 0xFFFFFFFF;
2224 InitializeObjectAttributes(&Obj
,
2229 Status
= MmCreateSection((PVOID
)&PhysSection
,
2233 PAGE_EXECUTE_READWRITE
,
2237 if (!NT_SUCCESS(Status
))
2239 DPRINT1("Failed to create PhysicalMemory section\n");
2242 Status
= ObInsertObject(PhysSection
,
2248 if (!NT_SUCCESS(Status
))
2250 ObDereferenceObject(PhysSection
);
2252 ObCloseHandle(Handle
, KernelMode
);
2253 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2254 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2256 return(STATUS_SUCCESS
);
2262 MmInitSectionImplementation(VOID
)
2264 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2265 UNICODE_STRING Name
;
2267 DPRINT("Creating Section Object Type\n");
2269 /* Initialize the Section object type */
2270 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2271 RtlInitUnicodeString(&Name
, L
"Section");
2272 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2273 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2274 ObjectTypeInitializer
.PoolType
= PagedPool
;
2275 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2276 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2277 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2278 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2279 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2280 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2282 return(STATUS_SUCCESS
);
2287 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2288 ACCESS_MASK DesiredAccess
,
2289 POBJECT_ATTRIBUTES ObjectAttributes
,
2290 PLARGE_INTEGER UMaximumSize
,
2291 ULONG SectionPageProtection
,
2292 ULONG AllocationAttributes
)
2294 * Create a section which is backed by the pagefile
2297 LARGE_INTEGER MaximumSize
;
2298 PROS_SECTION_OBJECT Section
;
2299 PMM_SECTION_SEGMENT Segment
;
2302 if (UMaximumSize
== NULL
)
2304 return(STATUS_UNSUCCESSFUL
);
2306 MaximumSize
= *UMaximumSize
;
2309 * Create the section
2311 Status
= ObCreateObject(ExGetPreviousMode(),
2312 MmSectionObjectType
,
2314 ExGetPreviousMode(),
2316 sizeof(ROS_SECTION_OBJECT
),
2319 (PVOID
*)(PVOID
)&Section
);
2320 if (!NT_SUCCESS(Status
))
2328 Section
->SectionPageProtection
= SectionPageProtection
;
2329 Section
->AllocationAttributes
= AllocationAttributes
;
2330 Section
->Segment
= NULL
;
2331 Section
->FileObject
= NULL
;
2332 Section
->MaximumSize
= MaximumSize
;
2333 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2334 TAG_MM_SECTION_SEGMENT
);
2335 if (Segment
== NULL
)
2337 ObDereferenceObject(Section
);
2338 return(STATUS_NO_MEMORY
);
2340 Section
->Segment
= Segment
;
2341 Segment
->ReferenceCount
= 1;
2342 ExInitializeFastMutex(&Segment
->Lock
);
2343 Segment
->FileOffset
= 0;
2344 Segment
->Protection
= SectionPageProtection
;
2345 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2346 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2347 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2348 Segment
->WriteCopy
= FALSE
;
2349 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2350 Segment
->VirtualAddress
= 0;
2351 Segment
->Characteristics
= 0;
2352 *SectionObject
= Section
;
2353 return(STATUS_SUCCESS
);
2359 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2360 ACCESS_MASK DesiredAccess
,
2361 POBJECT_ATTRIBUTES ObjectAttributes
,
2362 PLARGE_INTEGER UMaximumSize
,
2363 ULONG SectionPageProtection
,
2364 ULONG AllocationAttributes
,
2367 * Create a section backed by a data file
2370 PROS_SECTION_OBJECT Section
;
2372 LARGE_INTEGER MaximumSize
;
2373 PFILE_OBJECT FileObject
;
2374 PMM_SECTION_SEGMENT Segment
;
2376 IO_STATUS_BLOCK Iosb
;
2377 LARGE_INTEGER Offset
;
2379 FILE_STANDARD_INFORMATION FileInfo
;
2382 * Create the section
2384 Status
= ObCreateObject(ExGetPreviousMode(),
2385 MmSectionObjectType
,
2387 ExGetPreviousMode(),
2389 sizeof(ROS_SECTION_OBJECT
),
2392 (PVOID
*)(PVOID
)&Section
);
2393 if (!NT_SUCCESS(Status
))
2400 Section
->SectionPageProtection
= SectionPageProtection
;
2401 Section
->AllocationAttributes
= AllocationAttributes
;
2402 Section
->Segment
= NULL
;
2405 * Check file access required
2407 if (SectionPageProtection
& PAGE_READWRITE
||
2408 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2410 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2414 FileAccess
= FILE_READ_DATA
;
2418 * Reference the file handle
2420 Status
= ObReferenceObjectByHandle(FileHandle
,
2423 ExGetPreviousMode(),
2424 (PVOID
*)(PVOID
)&FileObject
,
2426 if (!NT_SUCCESS(Status
))
2428 ObDereferenceObject(Section
);
2433 * FIXME: This is propably not entirely correct. We can't look into
2434 * the standard FCB header because it might not be initialized yet
2435 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2436 * standard file information is filled on first request).
2438 Status
= IoQueryFileInformation(FileObject
,
2439 FileStandardInformation
,
2440 sizeof(FILE_STANDARD_INFORMATION
),
2443 if (!NT_SUCCESS(Status
))
2445 ObDereferenceObject(Section
);
2446 ObDereferenceObject(FileObject
);
2451 * FIXME: Revise this once a locking order for file size changes is
2454 if (UMaximumSize
!= NULL
)
2456 MaximumSize
= *UMaximumSize
;
2460 MaximumSize
= FileInfo
.EndOfFile
;
2461 /* Mapping zero-sized files isn't allowed. */
2462 if (MaximumSize
.QuadPart
== 0)
2464 ObDereferenceObject(Section
);
2465 ObDereferenceObject(FileObject
);
2466 return STATUS_FILE_INVALID
;
2470 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2472 Status
= IoSetInformation(FileObject
,
2473 FileAllocationInformation
,
2474 sizeof(LARGE_INTEGER
),
2476 if (!NT_SUCCESS(Status
))
2478 ObDereferenceObject(Section
);
2479 ObDereferenceObject(FileObject
);
2480 return(STATUS_SECTION_NOT_EXTENDED
);
2484 if (FileObject
->SectionObjectPointer
== NULL
||
2485 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2488 * Read a bit so caching is initiated for the file object.
2489 * This is only needed because MiReadPage currently cannot
2490 * handle non-cached streams.
2492 Offset
.QuadPart
= 0;
2493 Status
= ZwReadFile(FileHandle
,
2502 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2504 ObDereferenceObject(Section
);
2505 ObDereferenceObject(FileObject
);
2508 if (FileObject
->SectionObjectPointer
== NULL
||
2509 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2511 /* FIXME: handle this situation */
2512 ObDereferenceObject(Section
);
2513 ObDereferenceObject(FileObject
);
2514 return STATUS_INVALID_PARAMETER
;
2521 Status
= MmspWaitForFileLock(FileObject
);
2522 if (Status
!= STATUS_SUCCESS
)
2524 ObDereferenceObject(Section
);
2525 ObDereferenceObject(FileObject
);
2530 * If this file hasn't been mapped as a data file before then allocate a
2531 * section segment to describe the data file mapping
2533 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2535 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2536 TAG_MM_SECTION_SEGMENT
);
2537 if (Segment
== NULL
)
2539 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2540 ObDereferenceObject(Section
);
2541 ObDereferenceObject(FileObject
);
2542 return(STATUS_NO_MEMORY
);
2544 Section
->Segment
= Segment
;
2545 Segment
->ReferenceCount
= 1;
2546 ExInitializeFastMutex(&Segment
->Lock
);
2548 * Set the lock before assigning the segment to the file object
2550 ExAcquireFastMutex(&Segment
->Lock
);
2551 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2553 Segment
->FileOffset
= 0;
2554 Segment
->Protection
= SectionPageProtection
;
2555 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2556 Segment
->Characteristics
= 0;
2557 Segment
->WriteCopy
= FALSE
;
2558 if (AllocationAttributes
& SEC_RESERVE
)
2560 Segment
->Length
= Segment
->RawLength
= 0;
2564 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2565 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2567 Segment
->VirtualAddress
= 0;
2568 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2573 * If the file is already mapped as a data file then we may need
2577 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2579 Section
->Segment
= Segment
;
2580 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2581 MmLockSectionSegment(Segment
);
2583 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2584 !(AllocationAttributes
& SEC_RESERVE
))
2586 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2587 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2590 MmUnlockSectionSegment(Segment
);
2591 Section
->FileObject
= FileObject
;
2592 Section
->MaximumSize
= MaximumSize
;
2593 CcRosReferenceCache(FileObject
);
2594 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2595 *SectionObject
= Section
;
2596 return(STATUS_SUCCESS
);
2600 TODO: not that great (declaring loaders statically, having to declare all of
2601 them, having to keep them extern, etc.), will fix in the future
2603 extern NTSTATUS NTAPI PeFmtCreateSection
2605 IN CONST VOID
* FileHeader
,
2606 IN SIZE_T FileHeaderSize
,
2608 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2610 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2611 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2614 extern NTSTATUS NTAPI ElfFmtCreateSection
2616 IN CONST VOID
* FileHeader
,
2617 IN SIZE_T FileHeaderSize
,
2619 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2621 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2622 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2625 /* TODO: this is a standard DDK/PSDK macro */
2626 #ifndef RTL_NUMBER_OF
2627 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2630 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2641 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2643 SIZE_T SizeOfSegments
;
2644 PMM_SECTION_SEGMENT Segments
;
2646 /* TODO: check for integer overflow */
2647 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2649 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2651 TAG_MM_SECTION_SEGMENT
);
2654 RtlZeroMemory(Segments
, SizeOfSegments
);
2662 ExeFmtpReadFile(IN PVOID File
,
2663 IN PLARGE_INTEGER Offset
,
2666 OUT PVOID
* AllocBase
,
2667 OUT PULONG ReadSize
)
2670 LARGE_INTEGER FileOffset
;
2672 ULONG OffsetAdjustment
;
2677 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2681 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2684 FileOffset
= *Offset
;
2686 /* Negative/special offset: it cannot be used in this context */
2687 if(FileOffset
.u
.HighPart
< 0)
2689 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2692 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2693 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2694 FileOffset
.u
.LowPart
= AdjustOffset
;
2696 BufferSize
= Length
+ OffsetAdjustment
;
2697 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2700 * It's ok to use paged pool, because this is a temporary buffer only used in
2701 * the loading of executables. The assumption is that MmCreateSection is
2702 * always called at low IRQLs and that these buffers don't survive a brief
2703 * initialization phase
2705 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2707 TAG('M', 'm', 'X', 'r'));
2712 Status
= MmspPageRead(File
,
2719 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2720 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2721 * to initialize internal state is even worse. Our cache manager is in need of
2725 IO_STATUS_BLOCK Iosb
;
2727 Status
= ZwReadFile(File
,
2737 if(NT_SUCCESS(Status
))
2739 UsedSize
= Iosb
.Information
;
2744 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2746 Status
= STATUS_IN_PAGE_ERROR
;
2747 ASSERT(!NT_SUCCESS(Status
));
2750 if(NT_SUCCESS(Status
))
2752 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2753 *AllocBase
= Buffer
;
2754 *ReadSize
= UsedSize
- OffsetAdjustment
;
2765 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2766 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2767 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2772 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2776 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2778 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2779 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2786 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2790 MmspAssertSegmentsSorted(ImageSectionObject
);
2792 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2794 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2798 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2799 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2800 ImageSectionObject
->Segments
[i
- 1].Length
));
2808 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2812 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2814 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2815 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2823 MmspCompareSegments(const void * x
,
2826 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2827 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2830 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2831 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2835 * Ensures an image section's segments are sorted in memory
2840 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2843 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2845 MmspAssertSegmentsSorted(ImageSectionObject
);
2849 qsort(ImageSectionObject
->Segments
,
2850 ImageSectionObject
->NrSegments
,
2851 sizeof(ImageSectionObject
->Segments
[0]),
2852 MmspCompareSegments
);
2858 * Ensures an image section's segments don't overlap in memory and don't have
2859 * gaps and don't have a null size. We let them map to overlapping file regions,
2860 * though - that's not necessarily an error
2865 MmspCheckSegmentBounds
2867 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2873 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2875 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2879 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2881 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2883 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2891 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2892 * page could be OK (Windows seems to be OK with them), and larger gaps
2893 * could lead to image sections spanning several discontiguous regions
2894 * (NtMapViewOfSection could then refuse to map them, and they could
2895 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2897 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2898 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2899 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2910 * Merges and pads an image section's segments until they all are page-aligned
2911 * and have a size that is a multiple of the page size
2916 MmspPageAlignSegments
2918 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2924 BOOLEAN Initialized
;
2925 PMM_SECTION_SEGMENT EffectiveSegment
;
2927 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2929 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2933 Initialized
= FALSE
;
2935 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2937 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2940 * The first segment requires special handling
2944 ULONG_PTR VirtualAddress
;
2945 ULONG_PTR VirtualOffset
;
2947 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2949 /* Round down the virtual address to the nearest page */
2950 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2952 /* Round up the virtual size to the nearest page */
2953 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2954 EffectiveSegment
->VirtualAddress
;
2956 /* Adjust the raw address and size */
2957 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2959 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2965 * Garbage in, garbage out: unaligned base addresses make the file
2966 * offset point in curious and odd places, but that's what we were
2969 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2970 EffectiveSegment
->RawLength
+= VirtualOffset
;
2974 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2975 ULONG_PTR EndOfEffectiveSegment
;
2977 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2978 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2981 * The current segment begins exactly where the current effective
2982 * segment ended, therefore beginning a new effective segment
2984 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2987 ASSERT(LastSegment
<= i
);
2988 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2990 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2992 if (LastSegment
!= i
)
2995 * Copy the current segment. If necessary, the effective segment
2996 * will be expanded later
2998 *EffectiveSegment
= *Segment
;
3002 * Page-align the virtual size. We know for sure the virtual address
3005 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3006 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3009 * The current segment is still part of the current effective segment:
3010 * extend the effective segment to reflect this
3012 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3014 static const ULONG FlagsToProtection
[16] =
3022 PAGE_EXECUTE_READWRITE
,
3023 PAGE_EXECUTE_READWRITE
,
3028 PAGE_EXECUTE_WRITECOPY
,
3029 PAGE_EXECUTE_WRITECOPY
,
3030 PAGE_EXECUTE_WRITECOPY
,
3031 PAGE_EXECUTE_WRITECOPY
3034 unsigned ProtectionFlags
;
3037 * Extend the file size
3040 /* Unaligned segments must be contiguous within the file */
3041 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3042 EffectiveSegment
->RawLength
))
3047 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3050 * Extend the virtual size
3052 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3054 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3055 EffectiveSegment
->VirtualAddress
;
3058 * Merge the protection
3060 EffectiveSegment
->Protection
|= Segment
->Protection
;
3062 /* Clean up redundance */
3063 ProtectionFlags
= 0;
3065 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3066 ProtectionFlags
|= 1 << 0;
3068 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3069 ProtectionFlags
|= 1 << 1;
3071 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3072 ProtectionFlags
|= 1 << 2;
3074 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3075 ProtectionFlags
|= 1 << 3;
3077 ASSERT(ProtectionFlags
< 16);
3078 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3080 /* If a segment was required to be shared and cannot, fail */
3081 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3082 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3088 * We assume no holes between segments at this point
3096 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3102 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3103 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3105 LARGE_INTEGER Offset
;
3107 PVOID FileHeaderBuffer
;
3108 ULONG FileHeaderSize
;
3110 ULONG OldNrSegments
;
3115 * Read the beginning of the file (2 pages). Should be enough to contain
3116 * all (or most) of the headers
3118 Offset
.QuadPart
= 0;
3120 /* FIXME: use FileObject instead of FileHandle */
3121 Status
= ExeFmtpReadFile (FileHandle
,
3128 if (!NT_SUCCESS(Status
))
3131 if (FileHeaderSize
== 0)
3133 ExFreePool(FileHeaderBuffer
);
3134 return STATUS_UNSUCCESSFUL
;
3138 * Look for a loader that can handle this executable
3140 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3142 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3145 /* FIXME: use FileObject instead of FileHandle */
3146 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3152 ExeFmtpAllocateSegments
);
3154 if (!NT_SUCCESS(Status
))
3156 if (ImageSectionObject
->Segments
)
3158 ExFreePool(ImageSectionObject
->Segments
);
3159 ImageSectionObject
->Segments
= NULL
;
3163 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3167 ExFreePool(FileHeaderBuffer
);
3170 * No loader handled the format
3172 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3174 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3175 ASSERT(!NT_SUCCESS(Status
));
3178 if (!NT_SUCCESS(Status
))
3181 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3186 /* FIXME? are these values platform-dependent? */
3187 if(ImageSectionObject
->StackReserve
== 0)
3188 ImageSectionObject
->StackReserve
= 0x40000;
3190 if(ImageSectionObject
->StackCommit
== 0)
3191 ImageSectionObject
->StackCommit
= 0x1000;
3193 if(ImageSectionObject
->ImageBase
== 0)
3195 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3196 ImageSectionObject
->ImageBase
= 0x10000000;
3198 ImageSectionObject
->ImageBase
= 0x00400000;
3202 * And now the fun part: fixing the segments
3205 /* Sort them by virtual address */
3206 MmspSortSegments(ImageSectionObject
, Flags
);
3208 /* Ensure they don't overlap in memory */
3209 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3210 return STATUS_INVALID_IMAGE_FORMAT
;
3212 /* Ensure they are aligned */
3213 OldNrSegments
= ImageSectionObject
->NrSegments
;
3215 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3216 return STATUS_INVALID_IMAGE_FORMAT
;
3218 /* Trim them if the alignment phase merged some of them */
3219 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3221 PMM_SECTION_SEGMENT Segments
;
3222 SIZE_T SizeOfSegments
;
3224 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3226 Segments
= ExAllocatePoolWithTag(PagedPool
,
3228 TAG_MM_SECTION_SEGMENT
);
3230 if (Segments
== NULL
)
3231 return STATUS_INSUFFICIENT_RESOURCES
;
3233 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3234 ExFreePool(ImageSectionObject
->Segments
);
3235 ImageSectionObject
->Segments
= Segments
;
3238 /* And finish their initialization */
3239 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3241 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3242 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3244 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3245 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3248 ASSERT(NT_SUCCESS(Status
));
3253 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3254 ACCESS_MASK DesiredAccess
,
3255 POBJECT_ATTRIBUTES ObjectAttributes
,
3256 PLARGE_INTEGER UMaximumSize
,
3257 ULONG SectionPageProtection
,
3258 ULONG AllocationAttributes
,
3261 PROS_SECTION_OBJECT Section
;
3263 PFILE_OBJECT FileObject
;
3264 PMM_SECTION_SEGMENT SectionSegments
;
3265 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3267 ULONG FileAccess
= 0;
3270 * Specifying a maximum size is meaningless for an image section
3272 if (UMaximumSize
!= NULL
)
3274 return(STATUS_INVALID_PARAMETER_4
);
3278 * Check file access required
3280 if (SectionPageProtection
& PAGE_READWRITE
||
3281 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3283 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3287 FileAccess
= FILE_READ_DATA
;
3291 * Reference the file handle
3293 Status
= ObReferenceObjectByHandle(FileHandle
,
3296 ExGetPreviousMode(),
3297 (PVOID
*)(PVOID
)&FileObject
,
3300 if (!NT_SUCCESS(Status
))
3306 * Create the section
3308 Status
= ObCreateObject (ExGetPreviousMode(),
3309 MmSectionObjectType
,
3311 ExGetPreviousMode(),
3313 sizeof(ROS_SECTION_OBJECT
),
3316 (PVOID
*)(PVOID
)&Section
);
3317 if (!NT_SUCCESS(Status
))
3319 ObDereferenceObject(FileObject
);
3326 Section
->SectionPageProtection
= SectionPageProtection
;
3327 Section
->AllocationAttributes
= AllocationAttributes
;
3330 * Initialized caching for this file object if previously caching
3331 * was initialized for the same on disk file
3333 Status
= CcTryToInitializeFileCache(FileObject
);
3335 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3337 NTSTATUS StatusExeFmt
;
3339 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3340 if (ImageSectionObject
== NULL
)
3342 ObDereferenceObject(FileObject
);
3343 ObDereferenceObject(Section
);
3344 return(STATUS_NO_MEMORY
);
3347 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3349 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3351 if (!NT_SUCCESS(StatusExeFmt
))
3353 if(ImageSectionObject
->Segments
!= NULL
)
3354 ExFreePool(ImageSectionObject
->Segments
);
3356 ExFreePool(ImageSectionObject
);
3357 ObDereferenceObject(Section
);
3358 ObDereferenceObject(FileObject
);
3359 return(StatusExeFmt
);
3362 Section
->ImageSection
= ImageSectionObject
;
3363 ASSERT(ImageSectionObject
->Segments
);
3368 Status
= MmspWaitForFileLock(FileObject
);
3369 if (!NT_SUCCESS(Status
))
3371 ExFreePool(ImageSectionObject
->Segments
);
3372 ExFreePool(ImageSectionObject
);
3373 ObDereferenceObject(Section
);
3374 ObDereferenceObject(FileObject
);
3378 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3379 ImageSectionObject
, NULL
))
3382 * An other thread has initialized the some image in the background
3384 ExFreePool(ImageSectionObject
->Segments
);
3385 ExFreePool(ImageSectionObject
);
3386 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3387 Section
->ImageSection
= ImageSectionObject
;
3388 SectionSegments
= ImageSectionObject
->Segments
;
3390 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3392 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3396 Status
= StatusExeFmt
;
3403 Status
= MmspWaitForFileLock(FileObject
);
3404 if (Status
!= STATUS_SUCCESS
)
3406 ObDereferenceObject(Section
);
3407 ObDereferenceObject(FileObject
);
3411 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3412 Section
->ImageSection
= ImageSectionObject
;
3413 SectionSegments
= ImageSectionObject
->Segments
;
3416 * Otherwise just reference all the section segments
3418 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3420 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3423 Status
= STATUS_SUCCESS
;
3425 Section
->FileObject
= FileObject
;
3426 CcRosReferenceCache(FileObject
);
3427 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3428 *SectionObject
= Section
;
3436 NtCreateSection (OUT PHANDLE SectionHandle
,
3437 IN ACCESS_MASK DesiredAccess
,
3438 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3439 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3440 IN ULONG SectionPageProtection OPTIONAL
,
3441 IN ULONG AllocationAttributes
,
3442 IN HANDLE FileHandle OPTIONAL
)
3444 LARGE_INTEGER SafeMaximumSize
;
3445 PVOID SectionObject
;
3446 KPROCESSOR_MODE PreviousMode
;
3447 NTSTATUS Status
= STATUS_SUCCESS
;
3449 PreviousMode
= ExGetPreviousMode();
3451 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3455 /* make a copy on the stack */
3456 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3457 MaximumSize
= &SafeMaximumSize
;
3461 Status
= _SEH_GetExceptionCode();
3465 if(!NT_SUCCESS(Status
))
3471 Status
= MmCreateSection(&SectionObject
,
3475 SectionPageProtection
,
3476 AllocationAttributes
,
3479 if (NT_SUCCESS(Status
))
3481 Status
= ObInsertObject ((PVOID
)SectionObject
,
3493 /**********************************************************************
3511 NtOpenSection(PHANDLE SectionHandle
,
3512 ACCESS_MASK DesiredAccess
,
3513 POBJECT_ATTRIBUTES ObjectAttributes
)
3516 KPROCESSOR_MODE PreviousMode
;
3517 NTSTATUS Status
= STATUS_SUCCESS
;
3519 PreviousMode
= ExGetPreviousMode();
3521 if(PreviousMode
!= KernelMode
)
3525 ProbeForWriteHandle(SectionHandle
);
3529 Status
= _SEH_GetExceptionCode();
3533 if(!NT_SUCCESS(Status
))
3539 Status
= ObOpenObjectByName(ObjectAttributes
,
3540 MmSectionObjectType
,
3547 if(NT_SUCCESS(Status
))
3551 *SectionHandle
= hSection
;
3555 Status
= _SEH_GetExceptionCode();
3564 MmMapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3565 PROS_SECTION_OBJECT Section
,
3566 PMM_SECTION_SEGMENT Segment
,
3571 ULONG AllocationType
)
3575 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3577 BoundaryAddressMultiple
.QuadPart
= 0;
3579 Status
= MmCreateMemoryArea(AddressSpace
,
3580 MEMORY_AREA_SECTION_VIEW
,
3587 BoundaryAddressMultiple
);
3588 if (!NT_SUCCESS(Status
))
3590 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3591 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3595 ObReferenceObject((PVOID
)Section
);
3597 MArea
->Data
.SectionData
.Segment
= Segment
;
3598 MArea
->Data
.SectionData
.Section
= Section
;
3599 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3600 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3601 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3602 ViewSize
, 0, Protect
);
3604 return(STATUS_SUCCESS
);
3608 /**********************************************************************
3610 * NtMapViewOfSection
3613 * Maps a view of a section into the virtual address space of a
3618 * Handle of the section.
3621 * Handle of the process.
3624 * Desired base address (or NULL) on entry;
3625 * Actual base address of the view on exit.
3628 * Number of high order address bits that must be zero.
3631 * Size in bytes of the initially committed section of
3635 * Offset in bytes from the beginning of the section
3636 * to the beginning of the view.
3639 * Desired length of map (or zero to map all) on entry
3640 * Actual length mapped on exit.
3642 * InheritDisposition
3643 * Specified how the view is to be shared with
3647 * Type of allocation for the pages.
3650 * Protection for the committed region of the view.
3658 NtMapViewOfSection(IN HANDLE SectionHandle
,
3659 IN HANDLE ProcessHandle
,
3660 IN OUT PVOID
* BaseAddress OPTIONAL
,
3661 IN ULONG ZeroBits OPTIONAL
,
3662 IN ULONG CommitSize
,
3663 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3664 IN OUT PSIZE_T ViewSize
,
3665 IN SECTION_INHERIT InheritDisposition
,
3666 IN ULONG AllocationType OPTIONAL
,
3669 PVOID SafeBaseAddress
;
3670 LARGE_INTEGER SafeSectionOffset
;
3671 SIZE_T SafeViewSize
;
3672 PROS_SECTION_OBJECT Section
;
3674 KPROCESSOR_MODE PreviousMode
;
3675 PMADDRESS_SPACE AddressSpace
;
3676 NTSTATUS Status
= STATUS_SUCCESS
;
3680 * Check the protection
3682 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3685 return STATUS_INVALID_PARAMETER_10
;
3688 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3689 if (tmpProtect
!= PAGE_NOACCESS
&&
3690 tmpProtect
!= PAGE_READONLY
&&
3691 tmpProtect
!= PAGE_READWRITE
&&
3692 tmpProtect
!= PAGE_WRITECOPY
&&
3693 tmpProtect
!= PAGE_EXECUTE
&&
3694 tmpProtect
!= PAGE_EXECUTE_READ
&&
3695 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3696 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3699 return STATUS_INVALID_PAGE_PROTECTION
;
3702 PreviousMode
= ExGetPreviousMode();
3704 if(PreviousMode
!= KernelMode
)
3706 SafeBaseAddress
= NULL
;
3707 SafeSectionOffset
.QuadPart
= 0;
3712 if(BaseAddress
!= NULL
)
3714 ProbeForWritePointer(BaseAddress
);
3715 SafeBaseAddress
= *BaseAddress
;
3717 if(SectionOffset
!= NULL
)
3719 ProbeForWriteLargeInteger(SectionOffset
);
3720 SafeSectionOffset
= *SectionOffset
;
3722 ProbeForWriteSize_t(ViewSize
);
3723 SafeViewSize
= *ViewSize
;
3727 Status
= _SEH_GetExceptionCode();
3731 if(!NT_SUCCESS(Status
))
3738 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3739 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3740 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3743 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3745 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3746 PROCESS_VM_OPERATION
,
3749 (PVOID
*)(PVOID
)&Process
,
3751 if (!NT_SUCCESS(Status
))
3756 AddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
3758 Status
= ObReferenceObjectByHandle(SectionHandle
,
3760 MmSectionObjectType
,
3762 (PVOID
*)(PVOID
)&Section
,
3764 if (!(NT_SUCCESS(Status
)))
3766 DPRINT("ObReference failed rc=%x\n",Status
);
3767 ObDereferenceObject(Process
);
3771 Status
= MmMapViewOfSection(Section
,
3773 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3776 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3777 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3782 /* Check if this is an image for the current process */
3783 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3784 (Process
== PsGetCurrentProcess()) &&
3785 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3787 /* Notify the debugger */
3788 DbgkMapViewOfSection(Section
,
3790 SafeSectionOffset
.LowPart
,
3794 ObDereferenceObject(Section
);
3795 ObDereferenceObject(Process
);
3797 if(NT_SUCCESS(Status
))
3799 /* copy parameters back to the caller */
3802 if(BaseAddress
!= NULL
)
3804 *BaseAddress
= SafeBaseAddress
;
3806 if(SectionOffset
!= NULL
)
3808 *SectionOffset
= SafeSectionOffset
;
3810 if(ViewSize
!= NULL
)
3812 *ViewSize
= SafeViewSize
;
3817 Status
= _SEH_GetExceptionCode();
3826 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3827 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3830 PFILE_OBJECT FileObject
;
3833 SWAPENTRY SavedSwapEntry
;
3836 PROS_SECTION_OBJECT Section
;
3837 PMM_SECTION_SEGMENT Segment
;
3838 PMADDRESS_SPACE AddressSpace
;
3840 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3842 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3844 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3845 MemoryArea
->Data
.SectionData
.ViewOffset
;
3847 Section
= MemoryArea
->Data
.SectionData
.Section
;
3848 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3850 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3854 MmUnlockSectionSegment(Segment
);
3855 MmUnlockAddressSpace(AddressSpace
);
3857 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3858 if (Status
!= STATUS_SUCCESS
)
3860 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3864 MmLockAddressSpace(AddressSpace
);
3865 MmLockSectionSegment(Segment
);
3866 MmspCompleteAndReleasePageOp(PageOp
);
3867 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3870 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3873 * For a dirty, datafile, non-private page mark it as dirty in the
3876 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3878 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3880 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3881 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3882 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3883 ASSERT(SwapEntry
== 0);
3892 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3894 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3897 MmFreeSwapPage(SwapEntry
);
3901 if (IS_SWAP_FROM_SSE(Entry
) ||
3902 Page
!= PFN_FROM_SSE(Entry
))
3907 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3909 DPRINT1("Found a private page in a pagefile section.\n");
3913 * Just dereference private pages
3915 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3916 if (SavedSwapEntry
!= 0)
3918 MmFreeSwapPage(SavedSwapEntry
);
3919 MmSetSavedSwapEntryPage(Page
, 0);
3921 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3922 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3926 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3927 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3933 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3937 PMEMORY_AREA MemoryArea
;
3938 PROS_SECTION_OBJECT Section
;
3939 PMM_SECTION_SEGMENT Segment
;
3940 PLIST_ENTRY CurrentEntry
;
3941 PMM_REGION CurrentRegion
;
3942 PLIST_ENTRY RegionListHead
;
3944 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3946 if (MemoryArea
== NULL
)
3948 return(STATUS_UNSUCCESSFUL
);
3951 MemoryArea
->DeleteInProgress
= TRUE
;
3952 Section
= MemoryArea
->Data
.SectionData
.Section
;
3953 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3955 MmLockSectionSegment(Segment
);
3957 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3958 while (!IsListEmpty(RegionListHead
))
3960 CurrentEntry
= RemoveHeadList(RegionListHead
);
3961 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3962 ExFreePool(CurrentRegion
);
3965 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3967 Status
= MmFreeMemoryArea(AddressSpace
,
3974 Status
= MmFreeMemoryArea(AddressSpace
,
3979 MmUnlockSectionSegment(Segment
);
3980 ObDereferenceObject(Section
);
3981 return(STATUS_SUCCESS
);
3988 MmUnmapViewOfSection(PEPROCESS Process
,
3992 PMEMORY_AREA MemoryArea
;
3993 PMADDRESS_SPACE AddressSpace
;
3994 PROS_SECTION_OBJECT Section
;
3997 PVOID ImageBaseAddress
= 0;
3999 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4000 Process
, BaseAddress
);
4004 AddressSpace
= (PMADDRESS_SPACE
)&(Process
)->VadRoot
;
4006 MmLockAddressSpace(AddressSpace
);
4007 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4009 if (MemoryArea
== NULL
||
4010 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4011 MemoryArea
->DeleteInProgress
)
4013 MmUnlockAddressSpace(AddressSpace
);
4014 return STATUS_NOT_MAPPED_VIEW
;
4017 MemoryArea
->DeleteInProgress
= TRUE
;
4019 while (MemoryArea
->PageOpCount
)
4021 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4025 Offset
-= PAGE_SIZE
;
4026 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4027 MemoryArea
->Data
.SectionData
.Segment
,
4028 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4031 MmUnlockAddressSpace(AddressSpace
);
4032 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4033 if (Status
!= STATUS_SUCCESS
)
4035 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4038 MmLockAddressSpace(AddressSpace
);
4039 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4041 if (MemoryArea
== NULL
||
4042 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4044 MmUnlockAddressSpace(AddressSpace
);
4045 return STATUS_NOT_MAPPED_VIEW
;
4052 Section
= MemoryArea
->Data
.SectionData
.Section
;
4054 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4058 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4059 PMM_SECTION_SEGMENT SectionSegments
;
4060 PMM_SECTION_SEGMENT Segment
;
4062 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4063 ImageSectionObject
= Section
->ImageSection
;
4064 SectionSegments
= ImageSectionObject
->Segments
;
4065 NrSegments
= ImageSectionObject
->NrSegments
;
4067 /* Search for the current segment within the section segments
4068 * and calculate the image base address */
4069 for (i
= 0; i
< NrSegments
; i
++)
4071 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4073 if (Segment
== &SectionSegments
[i
])
4075 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4080 if (i
>= NrSegments
)
4085 for (i
= 0; i
< NrSegments
; i
++)
4087 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4089 PVOID SBaseAddress
= (PVOID
)
4090 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4092 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4098 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4101 /* Notify debugger */
4102 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4104 MmUnlockAddressSpace(AddressSpace
);
4105 return(STATUS_SUCCESS
);
4108 /**********************************************************************
4110 * NtUnmapViewOfSection
4125 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4129 KPROCESSOR_MODE PreviousMode
;
4132 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4133 ProcessHandle
, BaseAddress
);
4135 PreviousMode
= ExGetPreviousMode();
4137 DPRINT("Referencing process\n");
4138 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4139 PROCESS_VM_OPERATION
,
4142 (PVOID
*)(PVOID
)&Process
,
4144 if (!NT_SUCCESS(Status
))
4146 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4150 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4152 ObDereferenceObject(Process
);
4159 * Queries the information of a section object.
4161 * @param SectionHandle
4162 * Handle to the section object. It must be opened with SECTION_QUERY
4164 * @param SectionInformationClass
4165 * Index to a certain information structure. Can be either
4166 * SectionBasicInformation or SectionImageInformation. The latter
4167 * is valid only for sections that were created with the SEC_IMAGE
4169 * @param SectionInformation
4170 * Caller supplies storage for resulting information.
4172 * Size of the supplied storage.
4173 * @param ResultLength
4181 NtQuerySection(IN HANDLE SectionHandle
,
4182 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4183 OUT PVOID SectionInformation
,
4184 IN ULONG SectionInformationLength
,
4185 OUT PULONG ResultLength OPTIONAL
)
4187 PROS_SECTION_OBJECT Section
;
4188 KPROCESSOR_MODE PreviousMode
;
4189 NTSTATUS Status
= STATUS_SUCCESS
;
4191 PreviousMode
= ExGetPreviousMode();
4193 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4195 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4197 SectionInformationLength
,
4201 if(!NT_SUCCESS(Status
))
4203 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4207 Status
= ObReferenceObjectByHandle(SectionHandle
,
4209 MmSectionObjectType
,
4211 (PVOID
*)(PVOID
)&Section
,
4213 if (NT_SUCCESS(Status
))
4215 switch (SectionInformationClass
)
4217 case SectionBasicInformation
:
4219 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4223 Sbi
->Attributes
= Section
->AllocationAttributes
;
4224 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4226 Sbi
->BaseAddress
= 0;
4227 Sbi
->Size
.QuadPart
= 0;
4231 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4232 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4235 if (ResultLength
!= NULL
)
4237 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4239 Status
= STATUS_SUCCESS
;
4243 Status
= _SEH_GetExceptionCode();
4250 case SectionImageInformation
:
4252 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4256 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4257 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4259 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4260 ImageSectionObject
= Section
->ImageSection
;
4262 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4263 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4264 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4265 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4266 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4267 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4268 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4269 Sii
->Machine
= ImageSectionObject
->Machine
;
4270 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4273 if (ResultLength
!= NULL
)
4275 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4277 Status
= STATUS_SUCCESS
;
4281 Status
= _SEH_GetExceptionCode();
4289 ObDereferenceObject(Section
);
4297 * Extends size of file backed section.
4299 * @param SectionHandle
4300 * Handle to the section object. It must be opened with
4301 * SECTION_EXTEND_SIZE access.
4302 * @param NewMaximumSize
4303 * New maximum size of the section in bytes.
4307 * @todo Move the actual code to internal function MmExtendSection.
4311 NtExtendSection(IN HANDLE SectionHandle
,
4312 IN PLARGE_INTEGER NewMaximumSize
)
4314 LARGE_INTEGER SafeNewMaximumSize
;
4315 PROS_SECTION_OBJECT Section
;
4316 KPROCESSOR_MODE PreviousMode
;
4317 NTSTATUS Status
= STATUS_SUCCESS
;
4319 PreviousMode
= ExGetPreviousMode();
4321 if(PreviousMode
!= KernelMode
)
4325 /* make a copy on the stack */
4326 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4327 NewMaximumSize
= &SafeNewMaximumSize
;
4331 Status
= _SEH_GetExceptionCode();
4335 if(!NT_SUCCESS(Status
))
4341 Status
= ObReferenceObjectByHandle(SectionHandle
,
4342 SECTION_EXTEND_SIZE
,
4343 MmSectionObjectType
,
4347 if (!NT_SUCCESS(Status
))
4352 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4354 ObfDereferenceObject(Section
);
4355 return STATUS_INVALID_PARAMETER
;
4359 * - Acquire file extneding resource.
4360 * - Check if we're not resizing the section below it's actual size!
4361 * - Extend segments if needed.
4362 * - Set file information (FileAllocationInformation) to the new size.
4363 * - Release file extending resource.
4366 ObDereferenceObject(Section
);
4368 return STATUS_NOT_IMPLEMENTED
;
4372 /**********************************************************************
4374 * MmAllocateSection@4
4384 * Code taken from ntoskrnl/mm/special.c.
4389 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4394 PMADDRESS_SPACE AddressSpace
;
4395 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4397 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4399 BoundaryAddressMultiple
.QuadPart
= 0;
4401 AddressSpace
= MmGetKernelAddressSpace();
4402 Result
= BaseAddress
;
4403 MmLockAddressSpace(AddressSpace
);
4404 Status
= MmCreateMemoryArea (AddressSpace
,
4412 BoundaryAddressMultiple
);
4413 MmUnlockAddressSpace(AddressSpace
);
4415 if (!NT_SUCCESS(Status
))
4419 DPRINT("Result %p\n",Result
);
4421 /* Create a virtual mapping for this memory area */
4422 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4424 return ((PVOID
)Result
);
4428 /**********************************************************************
4430 * MmMapViewOfSection
4433 * Maps a view of a section into the virtual address space of a
4438 * Pointer to the section object.
4441 * Pointer to the process.
4444 * Desired base address (or NULL) on entry;
4445 * Actual base address of the view on exit.
4448 * Number of high order address bits that must be zero.
4451 * Size in bytes of the initially committed section of
4455 * Offset in bytes from the beginning of the section
4456 * to the beginning of the view.
4459 * Desired length of map (or zero to map all) on entry
4460 * Actual length mapped on exit.
4462 * InheritDisposition
4463 * Specified how the view is to be shared with
4467 * Type of allocation for the pages.
4470 * Protection for the committed region of the view.
4478 MmMapViewOfSection(IN PVOID SectionObject
,
4479 IN PEPROCESS Process
,
4480 IN OUT PVOID
*BaseAddress
,
4482 IN ULONG CommitSize
,
4483 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4484 IN OUT PSIZE_T ViewSize
,
4485 IN SECTION_INHERIT InheritDisposition
,
4486 IN ULONG AllocationType
,
4489 PROS_SECTION_OBJECT Section
;
4490 PMADDRESS_SPACE AddressSpace
;
4492 NTSTATUS Status
= STATUS_SUCCESS
;
4496 if (Protect
!= PAGE_READONLY
&&
4497 Protect
!= PAGE_READWRITE
&&
4498 Protect
!= PAGE_WRITECOPY
&&
4499 Protect
!= PAGE_EXECUTE
&&
4500 Protect
!= PAGE_EXECUTE_READ
&&
4501 Protect
!= PAGE_EXECUTE_READWRITE
&&
4502 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4505 return STATUS_INVALID_PAGE_PROTECTION
;
4509 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4510 AddressSpace
= (PMADDRESS_SPACE
)&(Process
)->VadRoot
;
4512 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4514 MmLockAddressSpace(AddressSpace
);
4516 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4520 ULONG_PTR ImageBase
;
4522 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4523 PMM_SECTION_SEGMENT SectionSegments
;
4525 ImageSectionObject
= Section
->ImageSection
;
4526 SectionSegments
= ImageSectionObject
->Segments
;
4527 NrSegments
= ImageSectionObject
->NrSegments
;
4530 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4533 ImageBase
= ImageSectionObject
->ImageBase
;
4537 for (i
= 0; i
< NrSegments
; i
++)
4539 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4541 ULONG_PTR MaxExtent
;
4542 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4543 SectionSegments
[i
].Length
;
4544 ImageSize
= max(ImageSize
, MaxExtent
);
4548 ImageSectionObject
->ImageSize
= ImageSize
;
4550 /* Check there is enough space to map the section at that point. */
4551 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4552 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4554 /* Fail if the user requested a fixed base address. */
4555 if ((*BaseAddress
) != NULL
)
4557 MmUnlockAddressSpace(AddressSpace
);
4558 return(STATUS_UNSUCCESSFUL
);
4560 /* Otherwise find a gap to map the image. */
4561 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4564 MmUnlockAddressSpace(AddressSpace
);
4565 return(STATUS_UNSUCCESSFUL
);
4569 for (i
= 0; i
< NrSegments
; i
++)
4571 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4573 PVOID SBaseAddress
= (PVOID
)
4574 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4575 MmLockSectionSegment(&SectionSegments
[i
]);
4576 Status
= MmMapViewOfSegment(AddressSpace
,
4578 &SectionSegments
[i
],
4580 SectionSegments
[i
].Length
,
4581 SectionSegments
[i
].Protection
,
4584 MmUnlockSectionSegment(&SectionSegments
[i
]);
4585 if (!NT_SUCCESS(Status
))
4587 MmUnlockAddressSpace(AddressSpace
);
4593 *BaseAddress
= (PVOID
)ImageBase
;
4597 /* check for write access */
4598 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4599 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4602 return STATUS_SECTION_PROTECTION
;
4604 /* check for read access */
4605 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4606 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4609 return STATUS_SECTION_PROTECTION
;
4611 /* check for execute access */
4612 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4613 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4616 return STATUS_SECTION_PROTECTION
;
4619 if (ViewSize
== NULL
)
4621 /* Following this pointer would lead to us to the dark side */
4622 /* What to do? Bugcheck? Return status? Do the mambo? */
4623 KEBUGCHECK(MEMORY_MANAGEMENT
);
4626 if (SectionOffset
== NULL
)
4632 ViewOffset
= SectionOffset
->u
.LowPart
;
4635 if ((ViewOffset
% PAGE_SIZE
) != 0)
4637 MmUnlockAddressSpace(AddressSpace
);
4638 return(STATUS_MAPPED_ALIGNMENT
);
4641 if ((*ViewSize
) == 0)
4643 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4645 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4647 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4650 MmLockSectionSegment(Section
->Segment
);
4651 Status
= MmMapViewOfSegment(AddressSpace
,
4658 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4659 MmUnlockSectionSegment(Section
->Segment
);
4660 if (!NT_SUCCESS(Status
))
4662 MmUnlockAddressSpace(AddressSpace
);
4667 MmUnlockAddressSpace(AddressSpace
);
4669 return(STATUS_SUCCESS
);
4676 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4677 IN PLARGE_INTEGER NewFileSize
)
4688 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4698 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4699 IN MMFLUSH_TYPE FlushType
)
4703 case MmFlushForDelete
:
4704 if (SectionObjectPointer
->ImageSectionObject
||
4705 SectionObjectPointer
->DataSectionObject
)
4709 CcRosSetRemoveOnClose(SectionObjectPointer
);
4711 case MmFlushForWrite
:
4721 MmForceSectionClosed (
4722 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4723 IN BOOLEAN DelayClose
)
4734 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4735 OUT PVOID
* MappedBase
,
4736 IN OUT PULONG ViewSize
)
4738 PROS_SECTION_OBJECT Section
;
4739 PMADDRESS_SPACE AddressSpace
;
4742 DPRINT("MmMapViewInSystemSpace() called\n");
4744 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4745 AddressSpace
= MmGetKernelAddressSpace();
4747 MmLockAddressSpace(AddressSpace
);
4750 if ((*ViewSize
) == 0)
4752 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4754 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4756 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4759 MmLockSectionSegment(Section
->Segment
);
4762 Status
= MmMapViewOfSegment(AddressSpace
,
4771 MmUnlockSectionSegment(Section
->Segment
);
4772 MmUnlockAddressSpace(AddressSpace
);
4782 MmMapViewInSessionSpace (
4784 OUT PVOID
*MappedBase
,
4785 IN OUT PSIZE_T ViewSize
4789 return STATUS_NOT_IMPLEMENTED
;
4797 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4799 PMADDRESS_SPACE AddressSpace
;
4802 DPRINT("MmUnmapViewInSystemSpace() called\n");
4804 AddressSpace
= MmGetKernelAddressSpace();
4806 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4816 MmUnmapViewInSessionSpace (
4821 return STATUS_NOT_IMPLEMENTED
;
4828 MmSetBankedSection (ULONG Unknown0
,
4836 return (STATUS_NOT_IMPLEMENTED
);
4840 /**********************************************************************
4845 * Creates a section object.
4848 * SectionObject (OUT)
4849 * Caller supplied storage for the resulting pointer
4850 * to a SECTION_OBJECT instance;
4853 * Specifies the desired access to the section can be a
4855 * STANDARD_RIGHTS_REQUIRED |
4857 * SECTION_MAP_WRITE |
4858 * SECTION_MAP_READ |
4859 * SECTION_MAP_EXECUTE
4861 * ObjectAttributes [OPTIONAL]
4862 * Initialized attributes for the object can be used
4863 * to create a named section;
4866 * Maximizes the size of the memory section. Must be
4867 * non-NULL for a page-file backed section.
4868 * If value specified for a mapped file and the file is
4869 * not large enough, file will be extended.
4871 * SectionPageProtection
4872 * Can be a combination of:
4878 * AllocationAttributes
4879 * Can be a combination of:
4884 * Handle to a file to create a section mapped to a file
4885 * instead of a memory backed section;
4896 MmCreateSection (OUT PVOID
* Section
,
4897 IN ACCESS_MASK DesiredAccess
,
4898 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4899 IN PLARGE_INTEGER MaximumSize
,
4900 IN ULONG SectionPageProtection
,
4901 IN ULONG AllocationAttributes
,
4902 IN HANDLE FileHandle OPTIONAL
,
4903 IN PFILE_OBJECT File OPTIONAL
)
4906 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4909 * Check the protection
4911 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4912 if (Protection
!= PAGE_NOACCESS
&&
4913 Protection
!= PAGE_READONLY
&&
4914 Protection
!= PAGE_READWRITE
&&
4915 Protection
!= PAGE_WRITECOPY
&&
4916 Protection
!= PAGE_EXECUTE
&&
4917 Protection
!= PAGE_EXECUTE_READ
&&
4918 Protection
!= PAGE_EXECUTE_READWRITE
&&
4919 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4922 return STATUS_INVALID_PAGE_PROTECTION
;
4925 if (AllocationAttributes
& SEC_IMAGE
)
4927 return(MmCreateImageSection(SectionObject
,
4931 SectionPageProtection
,
4932 AllocationAttributes
,
4936 if (FileHandle
!= NULL
)
4938 return(MmCreateDataFileSection(SectionObject
,
4942 SectionPageProtection
,
4943 AllocationAttributes
,
4947 return(MmCreatePageFileSection(SectionObject
,
4951 SectionPageProtection
,
4952 AllocationAttributes
));
4957 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
4958 IN OUT PULONG NumberOfPages
,
4959 IN OUT PULONG UserPfnArray
)
4962 return STATUS_NOT_IMPLEMENTED
;
4967 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
4968 IN ULONG NumberOfPages
,
4969 IN OUT PULONG UserPfnArray
)
4972 return STATUS_NOT_IMPLEMENTED
;
4977 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
4978 IN ULONG NumberOfPages
,
4979 IN OUT PULONG UserPfnArray
)
4982 return STATUS_NOT_IMPLEMENTED
;
4987 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
4988 IN OUT PULONG NumberOfPages
,
4989 IN OUT PULONG UserPfnArray
)
4992 return STATUS_NOT_IMPLEMENTED
;
4997 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
4998 IN PVOID File2MappedAsFile
)
5001 return STATUS_NOT_IMPLEMENTED
;