3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/section.c
23 * PURPOSE: Implements section objects
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES *****************************************************************/
33 #include <internal/debug.h>
35 #include <reactos/exeformat.h>
37 /* TYPES *********************************************************************/
41 PSECTION_OBJECT Section
;
42 PMM_SECTION_SEGMENT Segment
;
47 MM_SECTION_PAGEOUT_CONTEXT
;
49 /* GLOBALS *******************************************************************/
51 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
53 static GENERIC_MAPPING MmpSectionMapping
= {
54 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
55 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
56 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
59 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
60 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
62 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
63 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
64 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
65 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
66 #define MAX_SHARE_COUNT 0x7FF
67 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
68 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
69 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
71 /* FUNCTIONS *****************************************************************/
73 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
76 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
77 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
78 * RETURNS: Status of the wait.
81 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
83 LARGE_INTEGER Timeout
;
84 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
86 Timeout
.QuadPart
= -100000000LL; // 10 sec
89 Timeout
.QuadPart
= -100000000; // 10 sec
92 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
97 * FUNCTION: Sets the page op completion event and releases the page op.
98 * ARGUMENTS: PMM_PAGEOP.
99 * RETURNS: In shorter time than it takes you to even read this
100 * description, so don't even think about geting a mug of coffee.
103 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
105 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
106 MmReleasePageOp(PageOp
);
111 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
112 * ARGUMENTS: PFILE_OBJECT to wait for.
113 * RETURNS: Status of the wait.
116 MmspWaitForFileLock(PFILE_OBJECT File
)
118 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
123 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
126 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
128 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
130 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
132 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
139 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
141 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
143 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
144 PMM_SECTION_SEGMENT SectionSegments
;
148 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
149 NrSegments
= ImageSectionObject
->NrSegments
;
150 SectionSegments
= ImageSectionObject
->Segments
;
151 for (i
= 0; i
< NrSegments
; i
++)
153 if (SectionSegments
[i
].ReferenceCount
!= 0)
155 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
156 SectionSegments
[i
].ReferenceCount
);
159 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
161 ExFreePool(ImageSectionObject
->Segments
);
162 ExFreePool(ImageSectionObject
);
163 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
165 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
167 PMM_SECTION_SEGMENT Segment
;
169 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
172 if (Segment
->ReferenceCount
!= 0)
174 DPRINT1("Data segment still referenced\n");
177 MmFreePageTablesSectionSegment(Segment
);
179 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
184 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
186 ExAcquireFastMutex(&Segment
->Lock
);
190 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
192 ExReleaseFastMutex(&Segment
->Lock
);
196 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
200 PSECTION_PAGE_TABLE Table
;
201 ULONG DirectoryOffset
;
204 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
206 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
210 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
211 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
215 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
216 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
217 TAG_SECTION_PAGE_TABLE
);
222 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
223 DPRINT("Table %x\n", Table
);
226 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
227 Table
->Entry
[TableOffset
] = Entry
;
232 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
235 PSECTION_PAGE_TABLE Table
;
237 ULONG DirectoryOffset
;
240 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
242 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
244 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
248 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
249 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
250 DPRINT("Table %x\n", Table
);
256 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
257 Entry
= Table
->Entry
[TableOffset
];
262 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
267 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
270 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
273 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
275 DPRINT1("Maximum share count reached\n");
278 if (IS_SWAP_FROM_SSE(Entry
))
282 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
283 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
287 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
288 PMM_SECTION_SEGMENT Segment
,
294 BOOLEAN IsDirectMapped
= FALSE
;
296 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
299 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
302 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
304 DPRINT1("Zero share count for unshare\n");
307 if (IS_SWAP_FROM_SSE(Entry
))
311 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
313 * If we reducing the share count of this entry to zero then set the entry
314 * to zero and tell the cache the page is no longer mapped.
316 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
318 PFILE_OBJECT FileObject
;
320 SWAPENTRY SavedSwapEntry
;
322 BOOLEAN IsImageSection
;
325 FileOffset
= Offset
+ Segment
->FileOffset
;
327 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
329 Page
= PFN_FROM_SSE(Entry
);
330 FileObject
= Section
->FileObject
;
331 if (FileObject
!= NULL
&&
332 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
335 if ((FileOffset
% PAGE_SIZE
) == 0 &&
336 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
339 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
340 IsDirectMapped
= TRUE
;
341 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
342 if (!NT_SUCCESS(Status
))
344 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
350 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
351 if (SavedSwapEntry
== 0)
354 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
355 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
359 * Try to page out this page and set the swap entry
360 * within the section segment. There exist no rmap entry
361 * for this page. The pager thread can't page out a
362 * page without a rmap entry.
364 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
368 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
371 MmReleasePageMemoryConsumer(MC_USER
, Page
);
377 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
378 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
386 * We hold all locks. Nobody can do something with the current
387 * process and the current segment (also not within an other process).
390 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
391 if (!NT_SUCCESS(Status
))
393 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
397 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
398 MmSetSavedSwapEntryPage(Page
, 0);
400 MmReleasePageMemoryConsumer(MC_USER
, Page
);
404 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
411 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
413 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
416 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
419 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
422 PCACHE_SEGMENT CacheSeg
;
423 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
424 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
427 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
435 MiReadPage(PMEMORY_AREA MemoryArea
,
439 * FUNCTION: Read a page for a section backed memory area.
441 * MemoryArea - Memory area to read the page for.
442 * Offset - Offset of the page to read.
443 * Page - Variable that receives a page contains the read data.
450 PCACHE_SEGMENT CacheSeg
;
451 PFILE_OBJECT FileObject
;
455 BOOLEAN IsImageSection
;
458 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
459 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
460 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
461 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
462 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
466 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
469 * If the file system is letting us go directly to the cache and the
470 * memory area was mapped at an offset in the file which is page aligned
471 * then get the related cache segment.
473 if ((FileOffset
% PAGE_SIZE
) == 0 &&
474 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
475 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
479 * Get the related cache segment; we use a lower level interface than
480 * filesystems do because it is safe for us to use an offset with a
481 * alignment less than the file system block size.
483 Status
= CcRosGetCacheSegment(Bcb
,
489 if (!NT_SUCCESS(Status
))
496 * If the cache segment isn't up to date then call the file
497 * system to read in the data.
499 Status
= ReadCacheSegment(CacheSeg
);
500 if (!NT_SUCCESS(Status
))
502 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
507 * Retrieve the page from the cache segment that we actually want.
509 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
510 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
512 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
517 ULONG CacheSegOffset
;
519 * Allocate a page, this is rather complicated by the possibility
520 * we might have to move other things out of memory
522 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
523 if (!NT_SUCCESS(Status
))
527 Status
= CcRosGetCacheSegment(Bcb
,
533 if (!NT_SUCCESS(Status
))
540 * If the cache segment isn't up to date then call the file
541 * system to read in the data.
543 Status
= ReadCacheSegment(CacheSeg
);
544 if (!NT_SUCCESS(Status
))
546 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
550 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
551 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
552 Length
= RawLength
- SegOffset
;
553 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
555 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
557 else if (CacheSegOffset
>= PAGE_SIZE
)
559 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
563 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
564 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
565 Status
= CcRosGetCacheSegment(Bcb
,
566 FileOffset
+ CacheSegOffset
,
571 if (!NT_SUCCESS(Status
))
573 ExUnmapPage(PageAddr
);
579 * If the cache segment isn't up to date then call the file
580 * system to read in the data.
582 Status
= ReadCacheSegment(CacheSeg
);
583 if (!NT_SUCCESS(Status
))
585 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
586 ExUnmapPage(PageAddr
);
590 if (Length
< PAGE_SIZE
)
592 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
596 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
599 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
600 ExUnmapPage(PageAddr
);
602 return(STATUS_SUCCESS
);
606 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
607 MEMORY_AREA
* MemoryArea
,
615 PSECTION_OBJECT Section
;
616 PMM_SECTION_SEGMENT Segment
;
625 * There is a window between taking the page fault and locking the
626 * address space when another thread could load the page so we check
629 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
633 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
635 return(STATUS_SUCCESS
);
638 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
639 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
641 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
642 Section
= MemoryArea
->Data
.SectionData
.Section
;
643 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
644 &MemoryArea
->Data
.SectionData
.RegionListHead
,
649 MmLockSectionSegment(Segment
);
652 * Check if this page needs to be mapped COW
654 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
655 (Region
->Protect
== PAGE_READWRITE
||
656 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
658 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
662 Attributes
= Region
->Protect
;
666 * Get or create a page operation descriptor
668 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
671 DPRINT1("MmGetPageOp failed\n");
676 * Check if someone else is already handling this fault, if so wait
679 if (PageOp
->Thread
!= PsGetCurrentThread())
681 MmUnlockSectionSegment(Segment
);
682 MmUnlockAddressSpace(AddressSpace
);
683 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
685 * Check for various strange conditions
687 if (Status
!= STATUS_SUCCESS
)
689 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
692 if (PageOp
->Status
== STATUS_PENDING
)
694 DPRINT1("Woke for page op before completion\n");
697 MmLockAddressSpace(AddressSpace
);
699 * If this wasn't a pagein then restart the operation
701 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
703 MmspCompleteAndReleasePageOp(PageOp
);
704 DPRINT("Address 0x%.8X\n", Address
);
705 return(STATUS_MM_RESTART_OPERATION
);
709 * If the thread handling this fault has failed then we don't retry
711 if (!NT_SUCCESS(PageOp
->Status
))
713 Status
= PageOp
->Status
;
714 MmspCompleteAndReleasePageOp(PageOp
);
715 DPRINT("Address 0x%.8X\n", Address
);
718 MmLockSectionSegment(Segment
);
720 * If the completed fault was for another address space then set the
723 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
725 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
726 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
728 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
731 * The page was a private page in another or in our address space
733 MmUnlockSectionSegment(Segment
);
734 MmspCompleteAndReleasePageOp(PageOp
);
735 return(STATUS_MM_RESTART_OPERATION
);
738 Page
= PFN_FROM_SSE(Entry
);
740 MmSharePageEntrySectionSegment(Segment
, Offset
);
742 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
747 if (!NT_SUCCESS(Status
))
749 DbgPrint("Unable to create virtual mapping\n");
752 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
758 MmUnlockSectionSegment(Segment
);
759 PageOp
->Status
= STATUS_SUCCESS
;
760 MmspCompleteAndReleasePageOp(PageOp
);
761 DPRINT("Address 0x%.8X\n", Address
);
762 return(STATUS_SUCCESS
);
765 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
769 * Must be private page we have swapped out.
776 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
778 DPRINT1("Found a swaped out private page in a pagefile section.\n");
782 MmUnlockSectionSegment(Segment
);
783 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
785 MmUnlockAddressSpace(AddressSpace
);
786 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
787 if (!NT_SUCCESS(Status
))
792 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
793 if (!NT_SUCCESS(Status
))
795 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
798 MmLockAddressSpace(AddressSpace
);
799 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
804 if (!NT_SUCCESS(Status
))
806 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
812 * Store the swap entry for later use.
814 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
817 * Add the page to the process's working set
819 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
822 * Finish the operation
828 PageOp
->Status
= STATUS_SUCCESS
;
829 MmspCompleteAndReleasePageOp(PageOp
);
830 DPRINT("Address 0x%.8X\n", Address
);
831 return(STATUS_SUCCESS
);
835 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
837 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
839 MmUnlockSectionSegment(Segment
);
841 * Just map the desired physical page
843 Page
= (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
) >> PAGE_SHIFT
;
844 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
849 if (!NT_SUCCESS(Status
))
851 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
856 * Don't add an rmap entry since the page mapped could be for
865 * Cleanup and release locks
867 PageOp
->Status
= STATUS_SUCCESS
;
868 MmspCompleteAndReleasePageOp(PageOp
);
869 DPRINT("Address 0x%.8X\n", Address
);
870 return(STATUS_SUCCESS
);
874 * Map anonymous memory for BSS sections
876 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
)
878 MmUnlockSectionSegment(Segment
);
879 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
880 if (!NT_SUCCESS(Status
))
882 MmUnlockAddressSpace(AddressSpace
);
883 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
884 MmLockAddressSpace(AddressSpace
);
886 if (!NT_SUCCESS(Status
))
890 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
895 if (!NT_SUCCESS(Status
))
897 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
901 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
908 * Cleanup and release locks
910 PageOp
->Status
= STATUS_SUCCESS
;
911 MmspCompleteAndReleasePageOp(PageOp
);
912 DPRINT("Address 0x%.8X\n", Address
);
913 return(STATUS_SUCCESS
);
917 * Get the entry corresponding to the offset within the section
919 Offset
+= MemoryArea
->Data
.SectionData
.ViewOffset
;
920 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
925 * If the entry is zero (and it can't change because we have
926 * locked the segment) then we need to load the page.
930 * Release all our locks and read in the page from disk
932 MmUnlockSectionSegment(Segment
);
933 MmUnlockAddressSpace(AddressSpace
);
935 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
936 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
938 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
939 if (!NT_SUCCESS(Status
))
941 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
946 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
947 if (!NT_SUCCESS(Status
))
949 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
952 if (!NT_SUCCESS(Status
))
955 * FIXME: What do we know in this case?
958 * Cleanup and release locks
960 MmLockAddressSpace(AddressSpace
);
961 PageOp
->Status
= Status
;
962 MmspCompleteAndReleasePageOp(PageOp
);
963 DPRINT("Address 0x%.8X\n", Address
);
967 * Relock the address space and segment
969 MmLockAddressSpace(AddressSpace
);
970 MmLockSectionSegment(Segment
);
973 * Check the entry. No one should change the status of a page
974 * that has a pending page-in.
976 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
979 DbgPrint("Someone changed ppte entry while we slept\n");
984 * Mark the offset within the section as having valid, in-memory
987 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
988 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
989 MmUnlockSectionSegment(Segment
);
991 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
996 if (!NT_SUCCESS(Status
))
998 DbgPrint("Unable to create virtual mapping\n");
1001 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1007 PageOp
->Status
= STATUS_SUCCESS
;
1008 MmspCompleteAndReleasePageOp(PageOp
);
1009 DPRINT("Address 0x%.8X\n", Address
);
1010 return(STATUS_SUCCESS
);
1012 else if (IS_SWAP_FROM_SSE(Entry
))
1014 SWAPENTRY SwapEntry
;
1016 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1019 * Release all our locks and read in the page from disk
1021 MmUnlockSectionSegment(Segment
);
1023 MmUnlockAddressSpace(AddressSpace
);
1025 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1026 if (!NT_SUCCESS(Status
))
1031 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1032 if (!NT_SUCCESS(Status
))
1038 * Relock the address space and segment
1040 MmLockAddressSpace(AddressSpace
);
1041 MmLockSectionSegment(Segment
);
1044 * Check the entry. No one should change the status of a page
1045 * that has a pending page-in.
1047 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1048 if (Entry
!= Entry1
)
1050 DbgPrint("Someone changed ppte entry while we slept\n");
1055 * Mark the offset within the section as having valid, in-memory
1058 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1059 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1060 MmUnlockSectionSegment(Segment
);
1063 * Save the swap entry.
1065 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1066 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1071 if (!NT_SUCCESS(Status
))
1073 DbgPrint("Unable to create virtual mapping\n");
1076 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1081 PageOp
->Status
= STATUS_SUCCESS
;
1082 MmspCompleteAndReleasePageOp(PageOp
);
1083 DPRINT("Address 0x%.8X\n", Address
);
1084 return(STATUS_SUCCESS
);
1089 * If the section offset is already in-memory and valid then just
1090 * take another reference to the page
1093 Page
= PFN_FROM_SSE(Entry
);
1095 MmSharePageEntrySectionSegment(Segment
, Offset
);
1096 MmUnlockSectionSegment(Segment
);
1098 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1103 if (!NT_SUCCESS(Status
))
1105 DbgPrint("Unable to create virtual mapping\n");
1108 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1113 PageOp
->Status
= STATUS_SUCCESS
;
1114 MmspCompleteAndReleasePageOp(PageOp
);
1115 DPRINT("Address 0x%.8X\n", Address
);
1116 return(STATUS_SUCCESS
);
1121 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1122 MEMORY_AREA
* MemoryArea
,
1126 PMM_SECTION_SEGMENT Segment
;
1127 PSECTION_OBJECT Section
;
1139 * Check if the page has been paged out or has already been set readwrite
1141 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1142 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1144 DPRINT("Address 0x%.8X\n", Address
);
1145 return(STATUS_SUCCESS
);
1149 * Find the offset of the page
1151 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1152 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1154 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1155 Section
= MemoryArea
->Data
.SectionData
.Section
;
1156 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1157 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1162 MmLockSectionSegment(Segment
);
1164 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1165 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1167 MmUnlockSectionSegment(Segment
);
1170 * Check if we are doing COW
1172 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1173 (Region
->Protect
== PAGE_READWRITE
||
1174 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1176 DPRINT("Address 0x%.8X\n", Address
);
1177 return(STATUS_UNSUCCESSFUL
);
1180 if (IS_SWAP_FROM_SSE(Entry
) ||
1181 PFN_FROM_SSE(Entry
) != OldPage
)
1183 /* This is a private page. We must only change the page protection. */
1184 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1185 return(STATUS_SUCCESS
);
1189 * Get or create a pageop
1191 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1192 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1195 DPRINT1("MmGetPageOp failed\n");
1200 * Wait for any other operations to complete
1202 if (PageOp
->Thread
!= PsGetCurrentThread())
1204 MmUnlockAddressSpace(AddressSpace
);
1205 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1207 * Check for various strange conditions
1209 if (Status
== STATUS_TIMEOUT
)
1211 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1214 if (PageOp
->Status
== STATUS_PENDING
)
1216 DPRINT1("Woke for page op before completion\n");
1220 * Restart the operation
1222 MmLockAddressSpace(AddressSpace
);
1223 MmspCompleteAndReleasePageOp(PageOp
);
1224 DPRINT("Address 0x%.8X\n", Address
);
1225 return(STATUS_MM_RESTART_OPERATION
);
1229 * Release locks now we have the pageop
1231 MmUnlockAddressSpace(AddressSpace
);
1236 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1237 if (!NT_SUCCESS(Status
))
1246 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1247 memcpy(NewAddress
, PAddress
, PAGE_SIZE
);
1248 ExUnmapPage(NewAddress
);
1251 * Delete the old entry.
1253 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1256 * Set the PTE to point to the new page
1258 MmLockAddressSpace(AddressSpace
);
1259 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1264 if (!NT_SUCCESS(Status
))
1266 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1270 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1271 if (!NT_SUCCESS(Status
))
1273 DbgPrint("Unable to create virtual mapping\n");
1278 MmLockPage(NewPage
);
1279 MmUnlockPage(OldPage
);
1283 * Unshare the old page.
1285 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1286 MmLockSectionSegment(Segment
);
1287 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1288 MmUnlockSectionSegment(Segment
);
1290 PageOp
->Status
= STATUS_SUCCESS
;
1291 MmspCompleteAndReleasePageOp(PageOp
);
1292 DPRINT("Address 0x%.8X\n", Address
);
1293 return(STATUS_SUCCESS
);
1297 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1299 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1303 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1304 MmDeleteVirtualMapping(Process
,
1311 PageOutContext
->WasDirty
= TRUE
;
1313 if (!PageOutContext
->Private
)
1315 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1316 PageOutContext
->Segment
,
1317 PageOutContext
->Offset
,
1318 PageOutContext
->WasDirty
,
1323 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1326 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1330 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1331 MEMORY_AREA
* MemoryArea
,
1336 MM_SECTION_PAGEOUT_CONTEXT Context
;
1337 SWAPENTRY SwapEntry
;
1341 PFILE_OBJECT FileObject
;
1343 BOOLEAN DirectMapped
;
1344 BOOLEAN IsImageSection
;
1346 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1349 * Get the segment and section.
1351 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1352 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1354 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1355 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1357 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1359 FileObject
= Context
.Section
->FileObject
;
1360 DirectMapped
= FALSE
;
1361 if (FileObject
!= NULL
&&
1362 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1364 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1367 * If the file system is letting us go directly to the cache and the
1368 * memory area was mapped at an offset in the file which is page aligned
1369 * then note this is a direct mapped page.
1371 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1372 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1374 DirectMapped
= TRUE
;
1380 * This should never happen since mappings of physical memory are never
1381 * placed in the rmap lists.
1383 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1385 DPRINT1("Trying to page out from physical memory section address 0x%X "
1386 "process %d\n", Address
,
1387 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1392 * Get the section segment entry and the physical address.
1394 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1395 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1397 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1398 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1401 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1402 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1405 * Prepare the context structure for the rmap delete call.
1407 Context
.WasDirty
= FALSE
;
1408 if (Context
.Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1409 IS_SWAP_FROM_SSE(Entry
) ||
1410 PFN_FROM_SSE(Entry
) != Page
)
1412 Context
.Private
= TRUE
;
1416 Context
.Private
= FALSE
;
1420 * Take an additional reference to the page or the cache segment.
1422 if (DirectMapped
&& !Context
.Private
)
1424 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1426 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1432 MmReferencePage(Page
);
1435 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1438 * If this wasn't a private page then we should have reduced the entry to
1439 * zero by deleting all the rmaps.
1441 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1443 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1444 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1451 * If the page wasn't dirty then we can just free it as for a readonly page.
1452 * Since we unmapped all the mappings above we know it will not suddenly
1454 * If the page is from a pagefile section and has no swap entry,
1455 * we can't free the page at this point.
1457 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1458 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1460 if (Context
.Private
)
1462 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1463 Context
.WasDirty
? "dirty" : "clean", Address
);
1466 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1468 MmSetSavedSwapEntryPage(Page
, 0);
1469 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1470 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1471 PageOp
->Status
= STATUS_SUCCESS
;
1472 MmspCompleteAndReleasePageOp(PageOp
);
1473 return(STATUS_SUCCESS
);
1476 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1478 if (Context
.Private
)
1480 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1481 Context
.WasDirty
? "dirty" : "clean", Address
);
1484 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1486 MmSetSavedSwapEntryPage(Page
, 0);
1489 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1491 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1492 PageOp
->Status
= STATUS_SUCCESS
;
1493 MmspCompleteAndReleasePageOp(PageOp
);
1494 return(STATUS_SUCCESS
);
1497 else if (!Context
.Private
&& DirectMapped
)
1501 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1505 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1506 if (!NT_SUCCESS(Status
))
1508 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1511 PageOp
->Status
= STATUS_SUCCESS
;
1512 MmspCompleteAndReleasePageOp(PageOp
);
1513 return(STATUS_SUCCESS
);
1515 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1519 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1523 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1524 PageOp
->Status
= STATUS_SUCCESS
;
1525 MmspCompleteAndReleasePageOp(PageOp
);
1526 return(STATUS_SUCCESS
);
1528 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1530 MmSetSavedSwapEntryPage(Page
, 0);
1531 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1534 if (!NT_SUCCESS(Status
))
1538 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1539 PageOp
->Status
= STATUS_SUCCESS
;
1540 MmspCompleteAndReleasePageOp(PageOp
);
1541 return(STATUS_SUCCESS
);
1545 * If necessary, allocate an entry in the paging file for this page
1549 SwapEntry
= MmAllocSwapPage();
1552 MmShowOutOfSpaceMessagePagingFile();
1555 * For private pages restore the old mappings.
1557 if (Context
.Private
)
1559 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1561 MemoryArea
->Attributes
,
1564 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1566 MemoryArea
->Process
,
1572 * For non-private pages if the page wasn't direct mapped then
1573 * set it back into the section segment entry so we don't loose
1574 * our copy. Otherwise it will be handled by the cache manager.
1576 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1578 MemoryArea
->Attributes
,
1581 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1583 MemoryArea
->Process
,
1585 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1586 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1588 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1589 MmspCompleteAndReleasePageOp(PageOp
);
1590 return(STATUS_PAGEFILE_QUOTA
);
1595 * Write the page to the pagefile
1597 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1598 if (!NT_SUCCESS(Status
))
1600 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1603 * As above: undo our actions.
1604 * FIXME: Also free the swap page.
1606 if (Context
.Private
)
1608 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1610 MemoryArea
->Attributes
,
1613 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1615 MemoryArea
->Process
,
1620 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1622 MemoryArea
->Attributes
,
1625 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1627 MemoryArea
->Process
,
1629 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1630 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1632 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1633 MmspCompleteAndReleasePageOp(PageOp
);
1634 return(STATUS_UNSUCCESSFUL
);
1638 * Otherwise we have succeeded.
1640 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1641 MmSetSavedSwapEntryPage(Page
, 0);
1642 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1643 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1645 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1649 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1652 if (Context
.Private
)
1654 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1657 if (!NT_SUCCESS(Status
))
1664 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1665 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1668 PageOp
->Status
= STATUS_SUCCESS
;
1669 MmspCompleteAndReleasePageOp(PageOp
);
1670 return(STATUS_SUCCESS
);
1674 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1675 PMEMORY_AREA MemoryArea
,
1680 PSECTION_OBJECT Section
;
1681 PMM_SECTION_SEGMENT Segment
;
1683 SWAPENTRY SwapEntry
;
1687 PFILE_OBJECT FileObject
;
1689 BOOLEAN DirectMapped
;
1690 BOOLEAN IsImageSection
;
1692 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1694 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1697 * Get the segment and section.
1699 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1700 Section
= MemoryArea
->Data
.SectionData
.Section
;
1701 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1703 FileObject
= Section
->FileObject
;
1704 DirectMapped
= FALSE
;
1705 if (FileObject
!= NULL
&&
1706 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1708 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1711 * If the file system is letting us go directly to the cache and the
1712 * memory area was mapped at an offset in the file which is page aligned
1713 * then note this is a direct mapped page.
1715 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1716 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1718 DirectMapped
= TRUE
;
1723 * This should never happen since mappings of physical memory are never
1724 * placed in the rmap lists.
1726 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1728 DPRINT1("Trying to write back page from physical memory mapped at %X "
1729 "process %d\n", Address
,
1730 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1735 * Get the section segment entry and the physical address.
1737 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1738 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1740 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1741 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1744 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1745 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1748 * Check for a private (COWed) page.
1750 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1751 IS_SWAP_FROM_SSE(Entry
) ||
1752 PFN_FROM_SSE(Entry
) != Page
)
1762 * Speculatively set all mappings of the page to clean.
1764 MmSetCleanAllRmaps(Page
);
1767 * If this page was direct mapped from the cache then the cache manager
1768 * will take care of writing it back to disk.
1770 if (DirectMapped
&& !Private
)
1772 ASSERT(SwapEntry
== 0);
1773 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1774 PageOp
->Status
= STATUS_SUCCESS
;
1775 MmspCompleteAndReleasePageOp(PageOp
);
1776 return(STATUS_SUCCESS
);
1780 * If necessary, allocate an entry in the paging file for this page
1784 SwapEntry
= MmAllocSwapPage();
1787 MmSetDirtyAllRmaps(Page
);
1788 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1789 MmspCompleteAndReleasePageOp(PageOp
);
1790 return(STATUS_PAGEFILE_QUOTA
);
1792 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1796 * Write the page to the pagefile
1798 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1799 if (!NT_SUCCESS(Status
))
1801 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1803 MmSetDirtyAllRmaps(Page
);
1804 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1805 MmspCompleteAndReleasePageOp(PageOp
);
1806 return(STATUS_UNSUCCESSFUL
);
1810 * Otherwise we have succeeded.
1812 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1813 PageOp
->Status
= STATUS_SUCCESS
;
1814 MmspCompleteAndReleasePageOp(PageOp
);
1815 return(STATUS_SUCCESS
);
1819 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1827 PMEMORY_AREA MemoryArea
;
1828 PMM_SECTION_SEGMENT Segment
;
1832 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1833 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1835 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1836 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1841 if (OldProtect
!= NewProtect
)
1843 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1845 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1846 ULONG Protect
= NewProtect
;
1849 * If we doing COW for this segment then check if the page is
1852 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1858 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1859 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1860 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1862 Protect
= PAGE_READONLY
;
1863 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1864 IS_SWAP_FROM_SSE(Entry
) ||
1865 PFN_FROM_SSE(Entry
) != Page
)
1867 Protect
= NewProtect
;
1871 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1873 MmSetPageProtect(AddressSpace
->Process
, Address
,
1881 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1882 PMEMORY_AREA MemoryArea
,
1890 ULONG_PTR MaxLength
;
1892 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1893 if (Length
> MaxLength
)
1896 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1897 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1899 *OldProtect
= Region
->Protect
;
1900 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1901 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1902 BaseAddress
, Length
, Region
->Type
, Protect
,
1903 MmAlterViewAttributes
);
1909 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1911 PMEMORY_BASIC_INFORMATION Info
,
1912 PULONG ResultLength
)
1915 PVOID RegionBaseAddress
;
1916 PSECTION_OBJECT Section
;
1917 PLIST_ENTRY CurrentEntry
;
1918 PMEMORY_AREA CurrentMArea
;
1921 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1922 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1923 Address
, &RegionBaseAddress
);
1926 return STATUS_UNSUCCESSFUL
;
1928 Section
= MemoryArea
->Data
.SectionData
.Section
;
1929 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1931 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
1932 CurrentEntry
= Section
->ViewListHead
.Flink
;
1933 Info
->AllocationBase
= NULL
;
1934 while (CurrentEntry
!= &Section
->ViewListHead
)
1936 CurrentMArea
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Data
.SectionData
.ViewListEntry
);
1937 CurrentEntry
= CurrentEntry
->Flink
;
1938 if (Info
->AllocationBase
== NULL
)
1940 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1942 else if (CurrentMArea
->StartingAddress
< Info
->AllocationBase
)
1944 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1947 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
1948 Info
->BaseAddress
= RegionBaseAddress
;
1949 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1950 Info
->Type
= MEM_IMAGE
;
1954 Info
->BaseAddress
= RegionBaseAddress
;
1955 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1956 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1957 Info
->Type
= MEM_MAPPED
;
1959 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1960 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1961 Info
->State
= MEM_COMMIT
;
1962 Info
->Protect
= Region
->Protect
;
1964 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1965 return(STATUS_SUCCESS
);
1969 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1974 ULONG SavedSwapEntry
;
1979 Length
= PAGE_ROUND_UP(Segment
->Length
);
1980 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1982 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1985 if (IS_SWAP_FROM_SSE(Entry
))
1987 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1991 Page
= PFN_FROM_SSE(Entry
);
1992 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1993 if (SavedSwapEntry
!= 0)
1995 MmSetSavedSwapEntryPage(Page
, 0);
1996 MmFreeSwapPage(SavedSwapEntry
);
1998 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2000 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2006 MmpDeleteSection(PVOID ObjectBody
)
2008 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2010 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2011 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2016 PMM_SECTION_SEGMENT SectionSegments
;
2019 * NOTE: Section->ImageSection can be NULL for short time
2020 * during the section creating. If we fail for some reason
2021 * until the image section is properly initialized we shouldn't
2022 * process further here.
2024 if (Section
->ImageSection
== NULL
)
2027 SectionSegments
= Section
->ImageSection
->Segments
;
2028 NrSegments
= Section
->ImageSection
->NrSegments
;
2030 for (i
= 0; i
< NrSegments
; i
++)
2032 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2034 MmLockSectionSegment(&SectionSegments
[i
]);
2036 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2037 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2041 MmpFreePageFileSegment(&SectionSegments
[i
]);
2043 MmUnlockSectionSegment(&SectionSegments
[i
]);
2050 * NOTE: Section->Segment can be NULL for short time
2051 * during the section creating.
2053 if (Section
->Segment
== NULL
)
2056 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2058 MmpFreePageFileSegment(Section
->Segment
);
2059 MmFreePageTablesSectionSegment(Section
->Segment
);
2060 ExFreePool(Section
->Segment
);
2061 Section
->Segment
= NULL
;
2065 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2068 if (Section
->FileObject
!= NULL
)
2070 CcRosDereferenceCache(Section
->FileObject
);
2071 ObDereferenceObject(Section
->FileObject
);
2072 Section
->FileObject
= NULL
;
2077 MmpCloseSection(PVOID ObjectBody
,
2080 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2081 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2085 MmpCreateSection(PVOID ObjectBody
,
2087 PWSTR RemainingPath
,
2088 POBJECT_ATTRIBUTES ObjectAttributes
)
2090 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2091 ObjectBody
, Parent
, RemainingPath
);
2093 if (RemainingPath
== NULL
)
2095 return(STATUS_SUCCESS
);
2098 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2100 return(STATUS_UNSUCCESSFUL
);
2102 return(STATUS_SUCCESS
);
2105 NTSTATUS INIT_FUNCTION
2106 MmCreatePhysicalMemorySection(VOID
)
2108 PSECTION_OBJECT PhysSection
;
2110 OBJECT_ATTRIBUTES Obj
;
2111 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2112 LARGE_INTEGER SectionSize
;
2115 * Create the section mapping physical memory
2117 SectionSize
.QuadPart
= 0xFFFFFFFF;
2118 InitializeObjectAttributes(&Obj
,
2123 Status
= MmCreateSection(&PhysSection
,
2127 PAGE_EXECUTE_READWRITE
,
2131 if (!NT_SUCCESS(Status
))
2133 DbgPrint("Failed to create PhysicalMemory section\n");
2136 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2138 return(STATUS_SUCCESS
);
2141 NTSTATUS INIT_FUNCTION
2142 MmInitSectionImplementation(VOID
)
2144 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2146 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2148 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2149 MmSectionObjectType
->TotalObjects
= 0;
2150 MmSectionObjectType
->TotalHandles
= 0;
2151 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2152 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2153 MmSectionObjectType
->PagedPoolCharge
= 0;
2154 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2155 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2156 MmSectionObjectType
->Dump
= NULL
;
2157 MmSectionObjectType
->Open
= NULL
;
2158 MmSectionObjectType
->Close
= MmpCloseSection
;
2159 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2160 MmSectionObjectType
->Parse
= NULL
;
2161 MmSectionObjectType
->Security
= NULL
;
2162 MmSectionObjectType
->QueryName
= NULL
;
2163 MmSectionObjectType
->OkayToClose
= NULL
;
2164 MmSectionObjectType
->Create
= MmpCreateSection
;
2165 MmSectionObjectType
->DuplicationNotify
= NULL
;
2168 * NOTE: Do not register the section object type here because
2169 * the object manager it not initialized yet!
2170 * The section object type will be created in ObInit().
2172 ObpCreateTypeObject(MmSectionObjectType
);
2174 return(STATUS_SUCCESS
);
2178 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2179 ACCESS_MASK DesiredAccess
,
2180 POBJECT_ATTRIBUTES ObjectAttributes
,
2181 PLARGE_INTEGER UMaximumSize
,
2182 ULONG SectionPageProtection
,
2183 ULONG AllocationAttributes
)
2185 * Create a section which is backed by the pagefile
2188 LARGE_INTEGER MaximumSize
;
2189 PSECTION_OBJECT Section
;
2190 PMM_SECTION_SEGMENT Segment
;
2193 if (UMaximumSize
== NULL
)
2195 return(STATUS_UNSUCCESSFUL
);
2197 MaximumSize
= *UMaximumSize
;
2200 * Create the section
2202 Status
= ObCreateObject(ExGetPreviousMode(),
2203 MmSectionObjectType
,
2205 ExGetPreviousMode(),
2207 sizeof(SECTION_OBJECT
),
2210 (PVOID
*)(PVOID
)&Section
);
2211 if (!NT_SUCCESS(Status
))
2219 Section
->SectionPageProtection
= SectionPageProtection
;
2220 Section
->AllocationAttributes
= AllocationAttributes
;
2221 Section
->Segment
= NULL
;
2222 InitializeListHead(&Section
->ViewListHead
);
2223 KeInitializeSpinLock(&Section
->ViewListLock
);
2224 Section
->FileObject
= NULL
;
2225 Section
->MaximumSize
= MaximumSize
;
2226 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2227 TAG_MM_SECTION_SEGMENT
);
2228 if (Segment
== NULL
)
2230 ObDereferenceObject(Section
);
2231 return(STATUS_NO_MEMORY
);
2233 Section
->Segment
= Segment
;
2234 Segment
->ReferenceCount
= 1;
2235 ExInitializeFastMutex(&Segment
->Lock
);
2236 Segment
->FileOffset
= 0;
2237 Segment
->Protection
= SectionPageProtection
;
2238 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2239 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2240 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2241 Segment
->WriteCopy
= FALSE
;
2242 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2243 Segment
->VirtualAddress
= 0;
2244 Segment
->Characteristics
= 0;
2245 *SectionObject
= Section
;
2246 return(STATUS_SUCCESS
);
2251 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2252 ACCESS_MASK DesiredAccess
,
2253 POBJECT_ATTRIBUTES ObjectAttributes
,
2254 PLARGE_INTEGER UMaximumSize
,
2255 ULONG SectionPageProtection
,
2256 ULONG AllocationAttributes
,
2259 * Create a section backed by a data file
2262 PSECTION_OBJECT Section
;
2264 LARGE_INTEGER MaximumSize
;
2265 PFILE_OBJECT FileObject
;
2266 PMM_SECTION_SEGMENT Segment
;
2268 IO_STATUS_BLOCK Iosb
;
2269 LARGE_INTEGER Offset
;
2271 FILE_STANDARD_INFORMATION FileInfo
;
2274 * Create the section
2276 Status
= ObCreateObject(ExGetPreviousMode(),
2277 MmSectionObjectType
,
2279 ExGetPreviousMode(),
2281 sizeof(SECTION_OBJECT
),
2284 (PVOID
*)(PVOID
)&Section
);
2285 if (!NT_SUCCESS(Status
))
2293 Section
->SectionPageProtection
= SectionPageProtection
;
2294 Section
->AllocationAttributes
= AllocationAttributes
;
2295 Section
->Segment
= NULL
;
2296 InitializeListHead(&Section
->ViewListHead
);
2297 KeInitializeSpinLock(&Section
->ViewListLock
);
2300 * Check file access required
2302 if (SectionPageProtection
& PAGE_READWRITE
||
2303 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2305 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2309 FileAccess
= FILE_READ_DATA
;
2313 * Reference the file handle
2315 Status
= ObReferenceObjectByHandle(FileHandle
,
2319 (PVOID
*)(PVOID
)&FileObject
,
2321 if (!NT_SUCCESS(Status
))
2323 ObDereferenceObject(Section
);
2328 * FIXME: This is propably not entirely correct. We can't look into
2329 * the standard FCB header because it might not be initialized yet
2330 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2331 * standard file information is filled on first request).
2333 Status
= NtQueryInformationFile(FileHandle
,
2336 sizeof(FILE_STANDARD_INFORMATION
),
2337 FileStandardInformation
);
2338 if (!NT_SUCCESS(Status
))
2340 ObDereferenceObject(Section
);
2341 ObDereferenceObject(FileObject
);
2346 * FIXME: Revise this once a locking order for file size changes is
2349 if (UMaximumSize
!= NULL
)
2351 MaximumSize
= *UMaximumSize
;
2355 MaximumSize
= FileInfo
.EndOfFile
;
2356 /* Mapping zero-sized files isn't allowed. */
2357 if (MaximumSize
.QuadPart
== 0)
2359 ObDereferenceObject(Section
);
2360 ObDereferenceObject(FileObject
);
2361 return STATUS_FILE_INVALID
;
2365 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2367 Status
= NtSetInformationFile(FileHandle
,
2370 sizeof(LARGE_INTEGER
),
2371 FileAllocationInformation
);
2372 if (!NT_SUCCESS(Status
))
2374 ObDereferenceObject(Section
);
2375 ObDereferenceObject(FileObject
);
2376 return(STATUS_SECTION_NOT_EXTENDED
);
2380 if (FileObject
->SectionObjectPointer
== NULL
||
2381 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2384 * Read a bit so caching is initiated for the file object.
2385 * This is only needed because MiReadPage currently cannot
2386 * handle non-cached streams.
2388 Offset
.QuadPart
= 0;
2389 Status
= ZwReadFile(FileHandle
,
2398 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2400 ObDereferenceObject(Section
);
2401 ObDereferenceObject(FileObject
);
2404 if (FileObject
->SectionObjectPointer
== NULL
||
2405 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2407 /* FIXME: handle this situation */
2408 ObDereferenceObject(Section
);
2409 ObDereferenceObject(FileObject
);
2410 return STATUS_INVALID_PARAMETER
;
2417 Status
= MmspWaitForFileLock(FileObject
);
2418 if (Status
!= STATUS_SUCCESS
)
2420 ObDereferenceObject(Section
);
2421 ObDereferenceObject(FileObject
);
2426 * If this file hasn't been mapped as a data file before then allocate a
2427 * section segment to describe the data file mapping
2429 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2431 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2432 TAG_MM_SECTION_SEGMENT
);
2433 if (Segment
== NULL
)
2435 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2436 ObDereferenceObject(Section
);
2437 ObDereferenceObject(FileObject
);
2438 return(STATUS_NO_MEMORY
);
2440 Section
->Segment
= Segment
;
2441 Segment
->ReferenceCount
= 1;
2442 ExInitializeFastMutex(&Segment
->Lock
);
2444 * Set the lock before assigning the segment to the file object
2446 ExAcquireFastMutex(&Segment
->Lock
);
2447 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2449 Segment
->FileOffset
= 0;
2450 Segment
->Protection
= SectionPageProtection
;
2451 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2452 Segment
->Characteristics
= 0;
2453 Segment
->WriteCopy
= FALSE
;
2454 if (AllocationAttributes
& SEC_RESERVE
)
2456 Segment
->Length
= Segment
->RawLength
= 0;
2460 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2461 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2463 Segment
->VirtualAddress
= 0;
2464 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2469 * If the file is already mapped as a data file then we may need
2473 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2475 Section
->Segment
= Segment
;
2476 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2477 MmLockSectionSegment(Segment
);
2479 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2480 !(AllocationAttributes
& SEC_RESERVE
))
2482 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2483 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2486 MmUnlockSectionSegment(Segment
);
2487 Section
->FileObject
= FileObject
;
2488 Section
->MaximumSize
= MaximumSize
;
2489 CcRosReferenceCache(FileObject
);
2490 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2491 *SectionObject
= Section
;
2492 return(STATUS_SUCCESS
);
2496 TODO: not that great (declaring loaders statically, having to declare all of
2497 them, having to keep them extern, etc.), will fix in the future
2499 extern NTSTATUS NTAPI PeFmtCreateSection
2501 IN CONST VOID
* FileHeader
,
2502 IN SIZE_T FileHeaderSize
,
2504 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2506 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2507 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2510 extern NTSTATUS NTAPI ElfFmtCreateSection
2512 IN CONST VOID
* FileHeader
,
2513 IN SIZE_T FileHeaderSize
,
2515 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2517 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2518 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2521 /* TODO: this is a standard DDK/PSDK macro */
2522 #ifndef RTL_NUMBER_OF
2523 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2526 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2535 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2537 SIZE_T SizeOfSegments
;
2538 PMM_SECTION_SEGMENT Segments
;
2540 /* TODO: check for integer overflow */
2541 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2543 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2545 TAG_MM_SECTION_SEGMENT
);
2548 RtlZeroMemory(Segments
, SizeOfSegments
);
2556 ExeFmtpReadFile(IN PVOID File
,
2557 IN PLARGE_INTEGER Offset
,
2560 OUT PVOID
* AllocBase
,
2561 OUT PULONG ReadSize
)
2564 LARGE_INTEGER FileOffset
;
2566 ULONG OffsetAdjustment
;
2571 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2575 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2578 FileOffset
= *Offset
;
2580 /* Negative/special offset: it cannot be used in this context */
2581 if(FileOffset
.u
.HighPart
< 0)
2583 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2586 ASSERT(PAGE_SIZE
<= MAXULONG
);
2587 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2588 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2589 FileOffset
.u
.LowPart
= AdjustOffset
;
2591 BufferSize
= Length
+ OffsetAdjustment
;
2592 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2595 * It's ok to use paged pool, because this is a temporary buffer only used in
2596 * the loading of executables. The assumption is that MmCreateSection is
2597 * always called at low IRQLs and that these buffers don't survive a brief
2598 * initialization phase
2600 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2602 TAG('M', 'm', 'X', 'r'));
2607 Status
= MmspPageRead(File
,
2614 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2615 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2616 * to initialize internal state is even worse. Our cache manager is in need of
2620 IO_STATUS_BLOCK Iosb
;
2622 Status
= ZwReadFile(File
,
2632 if(NT_SUCCESS(Status
))
2634 UsedSize
= Iosb
.Information
;
2639 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2641 Status
= STATUS_IN_PAGE_ERROR
;
2642 ASSERT(!NT_SUCCESS(Status
));
2645 if(NT_SUCCESS(Status
))
2647 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2648 *AllocBase
= Buffer
;
2649 *ReadSize
= UsedSize
- OffsetAdjustment
;
2660 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2661 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2662 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2667 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2671 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2673 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2674 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2681 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2685 MmspAssertSegmentsSorted(ImageSectionObject
);
2687 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2689 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2693 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2694 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2695 ImageSectionObject
->Segments
[i
- 1].Length
));
2703 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2707 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2709 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2710 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2718 MmspCompareSegments(const void * x
,
2721 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2722 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2725 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2726 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2730 * Ensures an image section's segments are sorted in memory
2735 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2738 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2740 MmspAssertSegmentsSorted(ImageSectionObject
);
2744 qsort(ImageSectionObject
->Segments
,
2745 ImageSectionObject
->NrSegments
,
2746 sizeof(ImageSectionObject
->Segments
[0]),
2747 MmspCompareSegments
);
2753 * Ensures an image section's segments don't overlap in memory and don't have
2754 * gaps and don't have a null size. We let them map to overlapping file regions,
2755 * though - that's not necessarily an error
2760 MmspCheckSegmentBounds
2762 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2768 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2770 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2774 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2776 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2778 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2786 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2787 * page could be OK (Windows seems to be OK with them), and larger gaps
2788 * could lead to image sections spanning several discontiguous regions
2789 * (NtMapViewOfSection could then refuse to map them, and they could
2790 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2792 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2793 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2794 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2805 * Merges and pads an image section's segments until they all are page-aligned
2806 * and have a size that is a multiple of the page size
2811 MmspPageAlignSegments
2813 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2819 BOOLEAN Initialized
;
2821 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2823 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2827 Initialized
= FALSE
;
2830 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2832 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2835 * The first segment requires special handling
2839 ULONG_PTR VirtualAddress
;
2840 ULONG_PTR VirtualOffset
;
2842 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2844 /* Round down the virtual address to the nearest page */
2845 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2847 /* Round up the virtual size to the nearest page */
2848 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2849 EffectiveSegment
->VirtualAddress
;
2851 /* Adjust the raw address and size */
2852 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2854 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2860 * Garbage in, garbage out: unaligned base addresses make the file
2861 * offset point in curious and odd places, but that's what we were
2864 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2865 EffectiveSegment
->RawLength
+= VirtualOffset
;
2869 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2870 ULONG_PTR EndOfEffectiveSegment
;
2872 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2873 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2876 * The current segment begins exactly where the current effective
2877 * segment ended, therefore beginning a new effective segment
2879 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2882 ASSERT(LastSegment
<= i
);
2883 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2885 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2888 * Copy the current segment. If necessary, the effective segment
2889 * will be expanded later
2891 *EffectiveSegment
= *Segment
;
2894 * Page-align the virtual size. We know for sure the virtual address
2897 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2898 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2901 * The current segment is still part of the current effective segment:
2902 * extend the effective segment to reflect this
2904 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2906 static const ULONG FlagsToProtection
[16] =
2914 PAGE_EXECUTE_READWRITE
,
2915 PAGE_EXECUTE_READWRITE
,
2920 PAGE_EXECUTE_WRITECOPY
,
2921 PAGE_EXECUTE_WRITECOPY
,
2922 PAGE_EXECUTE_WRITECOPY
,
2923 PAGE_EXECUTE_WRITECOPY
2926 unsigned ProtectionFlags
;
2929 * Extend the file size
2932 /* Unaligned segments must be contiguous within the file */
2933 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2934 EffectiveSegment
->RawLength
))
2939 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2942 * Extend the virtual size
2944 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2946 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2947 EffectiveSegment
->VirtualAddress
;
2950 * Merge the protection
2952 EffectiveSegment
->Protection
|= Segment
->Protection
;
2954 /* Clean up redundance */
2955 ProtectionFlags
= 0;
2957 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2958 ProtectionFlags
|= 1 << 0;
2960 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2961 ProtectionFlags
|= 1 << 1;
2963 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2964 ProtectionFlags
|= 1 << 2;
2966 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2967 ProtectionFlags
|= 1 << 3;
2969 ASSERT(ProtectionFlags
< 16);
2970 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2972 /* If a segment was required to be shared and cannot, fail */
2973 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2974 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2980 * We assume no holes between segments at this point
2993 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2994 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2996 LARGE_INTEGER Offset
;
2998 PVOID FileHeaderBuffer
;
2999 ULONG FileHeaderSize
;
3001 ULONG OldNrSegments
;
3006 * Read the beginning of the file (2 pages). Should be enough to contain
3007 * all (or most) of the headers
3009 Offset
.QuadPart
= 0;
3011 /* FIXME: use FileObject instead of FileHandle */
3012 Status
= ExeFmtpReadFile (FileHandle
,
3019 if (!NT_SUCCESS(Status
))
3022 if (FileHeaderSize
== 0)
3024 ExFreePool(FileHeaderBuffer
);
3025 return STATUS_UNSUCCESSFUL
;
3029 * Look for a loader that can handle this executable
3031 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3033 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3036 /* FIXME: use FileObject instead of FileHandle */
3037 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3043 ExeFmtpAllocateSegments
);
3045 if (!NT_SUCCESS(Status
))
3047 if (ImageSectionObject
->Segments
)
3049 ExFreePool(ImageSectionObject
->Segments
);
3050 ImageSectionObject
->Segments
= NULL
;
3054 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3058 ExFreePool(FileHeaderBuffer
);
3061 * No loader handled the format
3063 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3065 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3066 ASSERT(!NT_SUCCESS(Status
));
3069 if (!NT_SUCCESS(Status
))
3072 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3077 /* FIXME? are these values platform-dependent? */
3078 if(ImageSectionObject
->StackReserve
== 0)
3079 ImageSectionObject
->StackReserve
= 0x40000;
3081 if(ImageSectionObject
->StackCommit
== 0)
3082 ImageSectionObject
->StackCommit
= 0x1000;
3084 if(ImageSectionObject
->ImageBase
== 0)
3086 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3087 ImageSectionObject
->ImageBase
= 0x10000000;
3089 ImageSectionObject
->ImageBase
= 0x00400000;
3093 * And now the fun part: fixing the segments
3096 /* Sort them by virtual address */
3097 MmspSortSegments(ImageSectionObject
, Flags
);
3099 /* Ensure they don't overlap in memory */
3100 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3101 return STATUS_INVALID_IMAGE_FORMAT
;
3103 /* Ensure they are aligned */
3104 OldNrSegments
= ImageSectionObject
->NrSegments
;
3106 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3107 return STATUS_INVALID_IMAGE_FORMAT
;
3109 /* Trim them if the alignment phase merged some of them */
3110 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3112 PMM_SECTION_SEGMENT Segments
;
3113 SIZE_T SizeOfSegments
;
3115 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3117 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3119 TAG_MM_SECTION_SEGMENT
);
3121 if (Segments
== NULL
)
3122 return STATUS_INSUFFICIENT_RESOURCES
;
3124 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3125 ExFreePool(ImageSectionObject
->Segments
);
3126 ImageSectionObject
->Segments
= Segments
;
3129 /* And finish their initialization */
3130 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3132 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3133 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3135 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3136 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3139 ASSERT(NT_SUCCESS(Status
));
3144 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3145 ACCESS_MASK DesiredAccess
,
3146 POBJECT_ATTRIBUTES ObjectAttributes
,
3147 PLARGE_INTEGER UMaximumSize
,
3148 ULONG SectionPageProtection
,
3149 ULONG AllocationAttributes
,
3152 PSECTION_OBJECT Section
;
3154 PFILE_OBJECT FileObject
;
3155 PMM_SECTION_SEGMENT SectionSegments
;
3156 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3158 ULONG FileAccess
= 0;
3161 * Specifying a maximum size is meaningless for an image section
3163 if (UMaximumSize
!= NULL
)
3165 return(STATUS_INVALID_PARAMETER_4
);
3169 * Check file access required
3171 if (SectionPageProtection
& PAGE_READWRITE
||
3172 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3174 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3178 FileAccess
= FILE_READ_DATA
;
3182 * Reference the file handle
3184 Status
= ObReferenceObjectByHandle(FileHandle
,
3188 (PVOID
*)(PVOID
)&FileObject
,
3190 if (!NT_SUCCESS(Status
))
3196 * Create the section
3198 Status
= ObCreateObject (ExGetPreviousMode(),
3199 MmSectionObjectType
,
3201 ExGetPreviousMode(),
3203 sizeof(SECTION_OBJECT
),
3206 (PVOID
*)(PVOID
)&Section
);
3207 if (!NT_SUCCESS(Status
))
3209 ObDereferenceObject(FileObject
);
3216 Section
->SectionPageProtection
= SectionPageProtection
;
3217 Section
->AllocationAttributes
= AllocationAttributes
;
3218 InitializeListHead(&Section
->ViewListHead
);
3219 KeInitializeSpinLock(&Section
->ViewListLock
);
3222 * Initialized caching for this file object if previously caching
3223 * was initialized for the same on disk file
3225 Status
= CcTryToInitializeFileCache(FileObject
);
3227 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3229 NTSTATUS StatusExeFmt
;
3231 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3232 if (ImageSectionObject
== NULL
)
3234 ObDereferenceObject(FileObject
);
3235 ObDereferenceObject(Section
);
3236 return(STATUS_NO_MEMORY
);
3239 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3241 if (!NT_SUCCESS(StatusExeFmt
))
3243 if(ImageSectionObject
->Segments
!= NULL
)
3244 ExFreePool(ImageSectionObject
->Segments
);
3246 ExFreePool(ImageSectionObject
);
3247 ObDereferenceObject(Section
);
3248 ObDereferenceObject(FileObject
);
3249 return(StatusExeFmt
);
3252 Section
->ImageSection
= ImageSectionObject
;
3253 ASSERT(ImageSectionObject
->Segments
);
3258 Status
= MmspWaitForFileLock(FileObject
);
3259 if (!NT_SUCCESS(Status
))
3261 ExFreePool(ImageSectionObject
->Segments
);
3262 ExFreePool(ImageSectionObject
);
3263 ObDereferenceObject(Section
);
3264 ObDereferenceObject(FileObject
);
3268 if (0 != InterlockedCompareExchangeUL(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3269 ImageSectionObject
, 0))
3272 * An other thread has initialized the some image in the background
3274 ExFreePool(ImageSectionObject
->Segments
);
3275 ExFreePool(ImageSectionObject
);
3276 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3277 Section
->ImageSection
= ImageSectionObject
;
3278 SectionSegments
= ImageSectionObject
->Segments
;
3280 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3282 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3286 Status
= StatusExeFmt
;
3293 Status
= MmspWaitForFileLock(FileObject
);
3294 if (Status
!= STATUS_SUCCESS
)
3296 ObDereferenceObject(Section
);
3297 ObDereferenceObject(FileObject
);
3301 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3302 Section
->ImageSection
= ImageSectionObject
;
3303 SectionSegments
= ImageSectionObject
->Segments
;
3306 * Otherwise just reference all the section segments
3308 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3310 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3313 Status
= STATUS_SUCCESS
;
3315 Section
->FileObject
= FileObject
;
3316 CcRosReferenceCache(FileObject
);
3317 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3318 *SectionObject
= Section
;
3326 NtCreateSection (OUT PHANDLE SectionHandle
,
3327 IN ACCESS_MASK DesiredAccess
,
3328 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3329 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3330 IN ULONG SectionPageProtection OPTIONAL
,
3331 IN ULONG AllocationAttributes
,
3332 IN HANDLE FileHandle OPTIONAL
)
3334 PSECTION_OBJECT SectionObject
;
3338 * Check the protection
3340 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3341 SectionPageProtection
)
3343 return(STATUS_INVALID_PAGE_PROTECTION
);
3346 Status
= MmCreateSection(&SectionObject
,
3350 SectionPageProtection
,
3351 AllocationAttributes
,
3355 if (NT_SUCCESS(Status
))
3357 Status
= ObInsertObject ((PVOID
)SectionObject
,
3363 ObDereferenceObject(SectionObject
);
3370 /**********************************************************************
3388 NtOpenSection(PHANDLE SectionHandle
,
3389 ACCESS_MASK DesiredAccess
,
3390 POBJECT_ATTRIBUTES ObjectAttributes
)
3396 Status
= ObOpenObjectByName(ObjectAttributes
,
3397 MmSectionObjectType
,
3408 MmMapViewOfSegment(PEPROCESS Process
,
3409 PMADDRESS_SPACE AddressSpace
,
3410 PSECTION_OBJECT Section
,
3411 PMM_SECTION_SEGMENT Segment
,
3421 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3423 BoundaryAddressMultiple
.QuadPart
= 0;
3425 Status
= MmCreateMemoryArea(Process
,
3427 MEMORY_AREA_SECTION_VIEW
,
3434 BoundaryAddressMultiple
);
3435 if (!NT_SUCCESS(Status
))
3437 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3438 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3442 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3443 InsertTailList(&Section
->ViewListHead
,
3444 &MArea
->Data
.SectionData
.ViewListEntry
);
3445 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3447 ObReferenceObjectByPointer((PVOID
)Section
,
3450 ExGetPreviousMode());
3451 MArea
->Data
.SectionData
.Segment
= Segment
;
3452 MArea
->Data
.SectionData
.Section
= Section
;
3453 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3454 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3455 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3456 ViewSize
, 0, Protect
);
3458 return(STATUS_SUCCESS
);
3462 /**********************************************************************
3464 * NtMapViewOfSection
3467 * Maps a view of a section into the virtual address space of a
3472 * Handle of the section.
3475 * Handle of the process.
3478 * Desired base address (or NULL) on entry;
3479 * Actual base address of the view on exit.
3482 * Number of high order address bits that must be zero.
3485 * Size in bytes of the initially committed section of
3489 * Offset in bytes from the beginning of the section
3490 * to the beginning of the view.
3493 * Desired length of map (or zero to map all) on entry
3494 * Actual length mapped on exit.
3496 * InheritDisposition
3497 * Specified how the view is to be shared with
3501 * Type of allocation for the pages.
3504 * Protection for the committed region of the view.
3512 NtMapViewOfSection(HANDLE SectionHandle
,
3513 HANDLE ProcessHandle
,
3517 PLARGE_INTEGER SectionOffset
,
3519 SECTION_INHERIT InheritDisposition
,
3520 ULONG AllocationType
,
3523 PSECTION_OBJECT Section
;
3526 PMADDRESS_SPACE AddressSpace
;
3528 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3529 PROCESS_VM_OPERATION
,
3532 (PVOID
*)(PVOID
)&Process
,
3534 if (!NT_SUCCESS(Status
))
3539 AddressSpace
= &Process
->AddressSpace
;
3541 Status
= ObReferenceObjectByHandle(SectionHandle
,
3543 MmSectionObjectType
,
3545 (PVOID
*)(PVOID
)&Section
,
3547 if (!(NT_SUCCESS(Status
)))
3549 DPRINT("ObReference failed rc=%x\n",Status
);
3550 ObDereferenceObject(Process
);
3554 Status
= MmMapViewOfSection(Section
,
3565 ObDereferenceObject(Section
);
3566 ObDereferenceObject(Process
);
3572 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3573 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3577 PFILE_OBJECT FileObject
;
3580 SWAPENTRY SavedSwapEntry
;
3583 PSECTION_OBJECT Section
;
3584 PMM_SECTION_SEGMENT Segment
;
3586 MArea
= (PMEMORY_AREA
)Context
;
3588 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3590 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->StartingAddress
) +
3591 MemoryArea
->Data
.SectionData
.ViewOffset
;
3593 Section
= MArea
->Data
.SectionData
.Section
;
3594 Segment
= MArea
->Data
.SectionData
.Segment
;
3596 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3600 MmUnlockSectionSegment(Segment
);
3601 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3603 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3604 if (Status
!= STATUS_SUCCESS
)
3606 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3610 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3611 MmLockSectionSegment(Segment
);
3612 MmspCompleteAndReleasePageOp(PageOp
);
3613 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3616 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3619 * For a dirty, datafile, non-private page mark it as dirty in the
3622 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3624 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3626 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3627 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3628 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3629 ASSERT(SwapEntry
== 0);
3638 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3640 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3643 MmFreeSwapPage(SwapEntry
);
3647 if (IS_SWAP_FROM_SSE(Entry
) ||
3648 Page
!= PFN_FROM_SSE(Entry
))
3653 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3655 DPRINT1("Found a private page in a pagefile section.\n");
3659 * Just dereference private pages
3661 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3662 if (SavedSwapEntry
!= 0)
3664 MmFreeSwapPage(SavedSwapEntry
);
3665 MmSetSavedSwapEntryPage(Page
, 0);
3667 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3668 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3672 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3673 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3679 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3683 PMEMORY_AREA MemoryArea
;
3684 PSECTION_OBJECT Section
;
3685 PMM_SECTION_SEGMENT Segment
;
3687 PLIST_ENTRY CurrentEntry
;
3688 PMM_REGION CurrentRegion
;
3689 PLIST_ENTRY RegionListHead
;
3691 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3693 if (MemoryArea
== NULL
)
3695 return(STATUS_UNSUCCESSFUL
);
3698 MemoryArea
->DeleteInProgress
= TRUE
;
3699 Section
= MemoryArea
->Data
.SectionData
.Section
;
3700 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3702 MmLockSectionSegment(Segment
);
3703 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3704 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3705 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3707 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3708 while (!IsListEmpty(RegionListHead
))
3710 CurrentEntry
= RemoveHeadList(RegionListHead
);
3711 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3712 ExFreePool(CurrentRegion
);
3715 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3717 Status
= MmFreeMemoryArea(AddressSpace
,
3724 Status
= MmFreeMemoryArea(AddressSpace
,
3729 MmUnlockSectionSegment(Segment
);
3730 ObDereferenceObject(Section
);
3731 return(STATUS_SUCCESS
);
3738 MmUnmapViewOfSection(PEPROCESS Process
,
3742 PMEMORY_AREA MemoryArea
;
3743 PMADDRESS_SPACE AddressSpace
;
3744 PSECTION_OBJECT Section
;
3746 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3747 Process
, BaseAddress
);
3751 AddressSpace
= &Process
->AddressSpace
;
3752 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3754 if (MemoryArea
== NULL
||
3755 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3756 MemoryArea
->DeleteInProgress
)
3758 return STATUS_NOT_MAPPED_VIEW
;
3761 Section
= MemoryArea
->Data
.SectionData
.Section
;
3763 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3767 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3768 PMM_SECTION_SEGMENT SectionSegments
;
3769 PVOID ImageBaseAddress
= 0;
3770 PMM_SECTION_SEGMENT Segment
;
3772 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3773 ImageSectionObject
= Section
->ImageSection
;
3774 SectionSegments
= ImageSectionObject
->Segments
;
3775 NrSegments
= ImageSectionObject
->NrSegments
;
3777 /* Search for the current segment within the section segments
3778 * and calculate the image base address */
3779 for (i
= 0; i
< NrSegments
; i
++)
3781 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3783 if (Segment
== &SectionSegments
[i
])
3785 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3790 if (i
>= NrSegments
)
3795 for (i
= 0; i
< NrSegments
; i
++)
3797 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3799 PVOID SBaseAddress
= (PVOID
)
3800 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3802 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3808 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3810 return(STATUS_SUCCESS
);
3813 /**********************************************************************
3815 * NtUnmapViewOfSection
3830 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3836 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3837 ProcessHandle
, BaseAddress
);
3839 DPRINT("Referencing process\n");
3840 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3841 PROCESS_VM_OPERATION
,
3844 (PVOID
*)(PVOID
)&Process
,
3846 if (!NT_SUCCESS(Status
))
3848 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3852 MmLockAddressSpace(&Process
->AddressSpace
);
3853 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3854 MmUnlockAddressSpace(&Process
->AddressSpace
);
3856 ObDereferenceObject(Process
);
3863 * Queries the information of a section object.
3865 * @param SectionHandle
3866 * Handle to the section object. It must be opened with SECTION_QUERY
3868 * @param SectionInformationClass
3869 * Index to a certain information structure. Can be either
3870 * SectionBasicInformation or SectionImageInformation. The latter
3871 * is valid only for sections that were created with the SEC_IMAGE
3873 * @param SectionInformation
3874 * Caller supplies storage for resulting information.
3876 * Size of the supplied storage.
3877 * @param ResultLength
3882 * @todo Guard by SEH.
3886 NtQuerySection(IN HANDLE SectionHandle
,
3887 IN CINT SectionInformationClass
,
3888 OUT PVOID SectionInformation
,
3890 OUT PULONG ResultLength
)
3892 PSECTION_OBJECT Section
;
3895 Status
= ObReferenceObjectByHandle(SectionHandle
,
3897 MmSectionObjectType
,
3899 (PVOID
*)(PVOID
)&Section
,
3901 if (!(NT_SUCCESS(Status
)))
3906 switch (SectionInformationClass
)
3908 case SectionBasicInformation
:
3910 PSECTION_BASIC_INFORMATION Sbi
;
3912 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3914 ObDereferenceObject(Section
);
3915 return(STATUS_INFO_LENGTH_MISMATCH
);
3918 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3920 Sbi
->Attributes
= Section
->AllocationAttributes
;
3921 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3923 Sbi
->BaseAddress
= 0;
3924 Sbi
->Size
.QuadPart
= 0;
3928 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
3929 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
3932 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3933 Status
= STATUS_SUCCESS
;
3937 case SectionImageInformation
:
3939 PSECTION_IMAGE_INFORMATION Sii
;
3941 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3943 ObDereferenceObject(Section
);
3944 return(STATUS_INFO_LENGTH_MISMATCH
);
3947 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3948 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3949 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3951 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3952 ImageSectionObject
= Section
->ImageSection
;
3954 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3955 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3956 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3957 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3958 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
3959 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
3960 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3961 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3962 Sii
->Executable
= ImageSectionObject
->Executable
;
3964 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3965 Status
= STATUS_SUCCESS
;
3971 Status
= STATUS_INVALID_INFO_CLASS
;
3973 ObDereferenceObject(Section
);
3979 * Extends size of file backed section.
3981 * @param SectionHandle
3982 * Handle to the section object. It must be opened with
3983 * SECTION_EXTEND_SIZE access.
3984 * @param NewMaximumSize
3985 * New maximum size of the section in bytes.
3989 * @todo Guard by SEH.
3990 * @todo Move the actual code to internal function MmExtendSection.
3994 NtExtendSection(IN HANDLE SectionHandle
,
3995 IN PLARGE_INTEGER NewMaximumSize
)
3997 PSECTION_OBJECT Section
;
4000 Status
= ObReferenceObjectByHandle(SectionHandle
,
4001 SECTION_EXTEND_SIZE
,
4002 MmSectionObjectType
,
4006 if (!NT_SUCCESS(Status
))
4011 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4013 ObfDereferenceObject(Section
);
4014 return STATUS_INVALID_PARAMETER
;
4018 * - Acquire file extneding resource.
4019 * - Check if we're not resizing the section below it's actual size!
4020 * - Extend segments if needed.
4021 * - Set file information (FileAllocationInformation) to the new size.
4022 * - Release file extending resource.
4025 ObDereferenceObject(Section
);
4027 return STATUS_NOT_IMPLEMENTED
;
4031 /**********************************************************************
4033 * MmAllocateSection@4
4043 * Code taken from ntoskrnl/mm/special.c.
4048 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4054 PMADDRESS_SPACE AddressSpace
;
4055 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4057 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4059 BoundaryAddressMultiple
.QuadPart
= 0;
4061 AddressSpace
= MmGetKernelAddressSpace();
4062 Result
= BaseAddress
;
4063 MmLockAddressSpace(AddressSpace
);
4064 Status
= MmCreateMemoryArea (NULL
,
4073 BoundaryAddressMultiple
);
4074 MmUnlockAddressSpace(AddressSpace
);
4076 if (!NT_SUCCESS(Status
))
4080 DPRINT("Result %p\n",Result
);
4081 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4085 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4086 if (!NT_SUCCESS(Status
))
4088 DbgPrint("Unable to allocate page\n");
4091 Status
= MmCreateVirtualMapping (NULL
,
4092 (PVOID
)(Result
+ (i
* PAGE_SIZE
)),
4096 if (!NT_SUCCESS(Status
))
4098 DbgPrint("Unable to create virtual mapping\n");
4102 return ((PVOID
)Result
);
4106 /**********************************************************************
4108 * MmMapViewOfSection
4111 * Maps a view of a section into the virtual address space of a
4116 * Pointer to the section object.
4119 * Pointer to the process.
4122 * Desired base address (or NULL) on entry;
4123 * Actual base address of the view on exit.
4126 * Number of high order address bits that must be zero.
4129 * Size in bytes of the initially committed section of
4133 * Offset in bytes from the beginning of the section
4134 * to the beginning of the view.
4137 * Desired length of map (or zero to map all) on entry
4138 * Actual length mapped on exit.
4140 * InheritDisposition
4141 * Specified how the view is to be shared with
4145 * Type of allocation for the pages.
4148 * Protection for the committed region of the view.
4156 MmMapViewOfSection(IN PVOID SectionObject
,
4157 IN PEPROCESS Process
,
4158 IN OUT PVOID
*BaseAddress
,
4160 IN ULONG CommitSize
,
4161 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4162 IN OUT PULONG ViewSize
,
4163 IN SECTION_INHERIT InheritDisposition
,
4164 IN ULONG AllocationType
,
4167 PSECTION_OBJECT Section
;
4168 PMADDRESS_SPACE AddressSpace
;
4170 NTSTATUS Status
= STATUS_SUCCESS
;
4174 Section
= (PSECTION_OBJECT
)SectionObject
;
4175 AddressSpace
= &Process
->AddressSpace
;
4177 MmLockAddressSpace(AddressSpace
);
4179 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4183 ULONG_PTR ImageBase
;
4185 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4186 PMM_SECTION_SEGMENT SectionSegments
;
4188 ImageSectionObject
= Section
->ImageSection
;
4189 SectionSegments
= ImageSectionObject
->Segments
;
4190 NrSegments
= ImageSectionObject
->NrSegments
;
4193 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4196 ImageBase
= ImageSectionObject
->ImageBase
;
4200 for (i
= 0; i
< NrSegments
; i
++)
4202 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4205 MaxExtent
= (ULONG
)((char*)SectionSegments
[i
].VirtualAddress
+
4206 SectionSegments
[i
].Length
);
4207 ImageSize
= max(ImageSize
, MaxExtent
);
4211 /* Check there is enough space to map the section at that point. */
4212 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4213 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4215 /* Fail if the user requested a fixed base address. */
4216 if ((*BaseAddress
) != NULL
)
4218 MmUnlockAddressSpace(AddressSpace
);
4219 return(STATUS_UNSUCCESSFUL
);
4221 /* Otherwise find a gap to map the image. */
4222 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4225 MmUnlockAddressSpace(AddressSpace
);
4226 return(STATUS_UNSUCCESSFUL
);
4230 for (i
= 0; i
< NrSegments
; i
++)
4232 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4234 PVOID SBaseAddress
= (PVOID
)
4235 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4236 MmLockSectionSegment(&SectionSegments
[i
]);
4237 Status
= MmMapViewOfSegment(Process
,
4240 &SectionSegments
[i
],
4242 SectionSegments
[i
].Length
,
4243 SectionSegments
[i
].Protection
,
4246 MmUnlockSectionSegment(&SectionSegments
[i
]);
4247 if (!NT_SUCCESS(Status
))
4249 MmUnlockAddressSpace(AddressSpace
);
4255 *BaseAddress
= (PVOID
)ImageBase
;
4259 if (ViewSize
== NULL
)
4261 /* Following this pointer would lead to us to the dark side */
4262 /* What to do? Bugcheck? Return status? Do the mambo? */
4263 KEBUGCHECK(MEMORY_MANAGEMENT
);
4266 if (SectionOffset
== NULL
)
4272 ViewOffset
= SectionOffset
->u
.LowPart
;
4275 if ((ViewOffset
% PAGE_SIZE
) != 0)
4277 MmUnlockAddressSpace(AddressSpace
);
4278 return(STATUS_MAPPED_ALIGNMENT
);
4281 if ((*ViewSize
) == 0)
4283 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4285 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4287 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4290 MmLockSectionSegment(Section
->Segment
);
4291 Status
= MmMapViewOfSegment(Process
,
4299 (AllocationType
& MEM_TOP_DOWN
));
4300 MmUnlockSectionSegment(Section
->Segment
);
4301 if (!NT_SUCCESS(Status
))
4303 MmUnlockAddressSpace(AddressSpace
);
4308 MmUnlockAddressSpace(AddressSpace
);
4310 return(STATUS_SUCCESS
);
4317 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4318 IN PLARGE_INTEGER NewFileSize
)
4329 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4339 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4340 IN MMFLUSH_TYPE FlushType
)
4344 case MmFlushForDelete
:
4345 if (SectionObjectPointer
->ImageSectionObject
||
4346 SectionObjectPointer
->DataSectionObject
)
4350 CcRosSetRemoveOnClose(SectionObjectPointer
);
4352 case MmFlushForWrite
:
4362 MmForceSectionClosed (
4363 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4364 IN BOOLEAN DelayClose
)
4375 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4376 OUT PVOID
* MappedBase
,
4377 IN OUT PULONG ViewSize
)
4379 PSECTION_OBJECT Section
;
4380 PMADDRESS_SPACE AddressSpace
;
4383 DPRINT("MmMapViewInSystemSpace() called\n");
4385 Section
= (PSECTION_OBJECT
)SectionObject
;
4386 AddressSpace
= MmGetKernelAddressSpace();
4388 MmLockAddressSpace(AddressSpace
);
4391 if ((*ViewSize
) == 0)
4393 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4395 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4397 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4400 MmLockSectionSegment(Section
->Segment
);
4403 Status
= MmMapViewOfSegment(NULL
,
4413 MmUnlockSectionSegment(Section
->Segment
);
4414 MmUnlockAddressSpace(AddressSpace
);
4424 MmMapViewInSessionSpace (
4426 OUT PVOID
*MappedBase
,
4427 IN OUT PSIZE_T ViewSize
4431 return STATUS_NOT_IMPLEMENTED
;
4439 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4441 PMADDRESS_SPACE AddressSpace
;
4444 DPRINT("MmUnmapViewInSystemSpace() called\n");
4446 AddressSpace
= MmGetKernelAddressSpace();
4448 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4458 MmUnmapViewInSessionSpace (
4463 return STATUS_NOT_IMPLEMENTED
;
4470 MmSetBankedSection (DWORD Unknown0
,
4478 return (STATUS_NOT_IMPLEMENTED
);
4482 /**********************************************************************
4487 * Creates a section object.
4490 * SectionObject (OUT)
4491 * Caller supplied storage for the resulting pointer
4492 * to a SECTION_OBJECT instance;
4495 * Specifies the desired access to the section can be a
4497 * STANDARD_RIGHTS_REQUIRED |
4499 * SECTION_MAP_WRITE |
4500 * SECTION_MAP_READ |
4501 * SECTION_MAP_EXECUTE
4503 * ObjectAttributes [OPTIONAL]
4504 * Initialized attributes for the object can be used
4505 * to create a named section;
4508 * Maximizes the size of the memory section. Must be
4509 * non-NULL for a page-file backed section.
4510 * If value specified for a mapped file and the file is
4511 * not large enough, file will be extended.
4513 * SectionPageProtection
4514 * Can be a combination of:
4520 * AllocationAttributes
4521 * Can be a combination of:
4526 * Handle to a file to create a section mapped to a file
4527 * instead of a memory backed section;
4538 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4539 IN ACCESS_MASK DesiredAccess
,
4540 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4541 IN PLARGE_INTEGER MaximumSize
,
4542 IN ULONG SectionPageProtection
,
4543 IN ULONG AllocationAttributes
,
4544 IN HANDLE FileHandle OPTIONAL
,
4545 IN PFILE_OBJECT File OPTIONAL
)
4547 if (AllocationAttributes
& SEC_IMAGE
)
4549 return(MmCreateImageSection(SectionObject
,
4553 SectionPageProtection
,
4554 AllocationAttributes
,
4558 if (FileHandle
!= NULL
)
4560 return(MmCreateDataFileSection(SectionObject
,
4564 SectionPageProtection
,
4565 AllocationAttributes
,
4569 return(MmCreatePageFileSection(SectionObject
,
4573 SectionPageProtection
,
4574 AllocationAttributes
));