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 *****************************************************************/
32 #define NTOS_MODE_KERNEL
34 #include <internal/mm.h>
35 #include <internal/io.h>
36 #include <internal/ps.h>
37 #include <internal/pool.h>
38 #include <internal/cc.h>
39 #include <ddk/ntifs.h>
40 #include <ntos/minmax.h>
43 #include <internal/debug.h>
45 /* TYPES *********************************************************************/
49 PSECTION_OBJECT Section;
50 PMM_SECTION_SEGMENT Segment;
54 } MM_SECTION_PAGEOUT_CONTEXT;
56 /* GLOBALS *******************************************************************/
58 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
60 static GENERIC_MAPPING MmpSectionMapping = {
61 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
62 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
63 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
66 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
67 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
69 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
70 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
71 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
72 #define MAX_SHARE_COUNT 0x7FF
73 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
74 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
75 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
77 /* FUNCTIONS *****************************************************************/
80 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
83 if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE)
85 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
87 if (Segment->PageDirectory.PageTables[i] != NULL)
89 ExFreePool(Segment->PageDirectory.PageTables[i]);
96 MmFreeSectionSegments(PFILE_OBJECT FileObject)
98 if (FileObject->SectionObjectPointer->ImageSectionObject != NULL)
100 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
101 PMM_SECTION_SEGMENT SectionSegments;
105 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject;
106 NrSegments = ImageSectionObject->NrSegments;
107 SectionSegments = ImageSectionObject->Segments;
108 for (i = 0; i < NrSegments; i++)
110 if (SectionSegments[i].ReferenceCount != 0)
112 DPRINT1("Image segment %d still referenced (was %d)\n", i,
113 SectionSegments[i].ReferenceCount);
116 MmFreePageTablesSectionSegment(&SectionSegments[i]);
118 ExFreePool(ImageSectionObject);
119 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
121 if (FileObject->SectionObjectPointer->DataSectionObject != NULL)
123 PMM_SECTION_SEGMENT Segment;
125 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
128 if (Segment->ReferenceCount != 0)
130 DPRINT1("Data segment still referenced\n");
133 MmFreePageTablesSectionSegment(Segment);
135 FileObject->SectionObjectPointer->DataSectionObject = NULL;
140 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
142 ExAcquireFastMutex(&Segment->Lock);
146 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
148 ExReleaseFastMutex(&Segment->Lock);
152 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
156 PSECTION_PAGE_TABLE Table;
157 ULONG DirectoryOffset;
160 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
162 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
166 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
167 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
171 Segment->PageDirectory.PageTables[DirectoryOffset] =
172 ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
173 TAG_SECTION_PAGE_TABLE);
178 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
179 DPRINT("Table %x\n", Table);
182 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
183 Table->Entry[TableOffset] = Entry;
188 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
191 PSECTION_PAGE_TABLE Table;
193 ULONG DirectoryOffset;
196 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
198 if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE)
200 Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory;
204 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
205 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
206 DPRINT("Table %x\n", Table);
212 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
213 Entry = Table->Entry[TableOffset];
218 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
223 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
226 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
229 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
231 DPRINT1("Maximum share count reached\n");
234 if (IS_SWAP_FROM_SSE(Entry))
238 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
239 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
243 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
244 PMM_SECTION_SEGMENT Segment,
250 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
253 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
256 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
258 DPRINT1("Zero share count for unshare\n");
261 if (IS_SWAP_FROM_SSE(Entry))
265 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
267 * If we reducing the share count of this entry to zero then set the entry
268 * to zero and tell the cache the page is no longer mapped.
270 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
272 PFILE_OBJECT FileObject;
274 SWAPENTRY SavedSwapEntry;
275 PHYSICAL_ADDRESS Page;
276 BOOLEAN IsImageSection;
279 FileOffset = Offset + Segment->FileOffset;
281 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
283 Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
284 FileObject = Section->FileObject;
285 if (FileObject != NULL)
288 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
289 (FileOffset % PAGE_SIZE) == 0 &&
290 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
293 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
294 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
295 if (!NT_SUCCESS(Status))
297 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
303 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
304 if (SavedSwapEntry == 0)
306 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
310 * Try to page out this page and set the swap entry
311 * within the section segment. There exist no rmap entry
312 * for this page. The pager thread can't page out a
313 * page without a rmap entry.
315 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
316 MmReferencePage(Page);
320 MmSetPageEntrySectionSegment(Segment, Offset, 0);
325 MmSetSavedSwapEntryPage(Page, 0);
326 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
328 MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
332 MmSetPageEntrySectionSegment(Segment, Offset, 0);
333 MmFreeSwapPage(SavedSwapEntry);
339 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
341 return(SHARE_COUNT_FROM_SSE(Entry) > 0);
344 BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea,
348 PCACHE_SEGMENT CacheSeg;
350 Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
351 CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset);
354 CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
361 MiReadPage(PMEMORY_AREA MemoryArea,
363 PHYSICAL_ADDRESS* Page)
365 * FUNCTION: Read a page for a section backed memory area.
367 * MemoryArea - Memory area to read the page for.
368 * Offset - Offset of the page to read.
369 * Page - Variable that receives a page contains the read data.
376 PCACHE_SEGMENT CacheSeg;
377 PFILE_OBJECT FileObject;
381 BOOLEAN IsImageSection;
384 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
385 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
386 RawLength = MemoryArea->Data.SectionData.Segment->RawLength;
387 FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset;
388 IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
392 DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset);
395 * If the file system is letting us go directly to the cache and the
396 * memory area was mapped at an offset in the file which is page aligned
397 * then get the related cache segment.
399 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
400 (FileOffset % PAGE_SIZE) == 0 &&
401 (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection))
403 PHYSICAL_ADDRESS Addr;
406 * Get the related cache segment; we use a lower level interface than
407 * filesystems do because it is safe for us to use an offset with a
408 * alignment less than the file system block size.
410 Status = CcRosGetCacheSegment(Bcb,
416 if (!NT_SUCCESS(Status))
423 * If the cache segment isn't up to date then call the file
424 * system to read in the data.
426 Status = ReadCacheSegment(CacheSeg);
427 if (!NT_SUCCESS(Status))
429 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
434 * Retrieve the page from the cache segment that we actually want.
436 Addr = MmGetPhysicalAddress(BaseAddress +
437 FileOffset - BaseOffset);
439 MmReferencePage((*Page));
441 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE);
446 ULONG CacheSegOffset;
448 * Allocate a page, this is rather complicated by the possibility
449 * we might have to move other things out of memory
451 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
452 if (!NT_SUCCESS(Status))
456 Status = CcRosGetCacheSegment(Bcb,
462 if (!NT_SUCCESS(Status))
469 * If the cache segment isn't up to date then call the file
470 * system to read in the data.
472 Status = ReadCacheSegment(CacheSeg);
473 if (!NT_SUCCESS(Status))
475 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
479 PageAddr = ExAllocatePageWithPhysPage(*Page);
480 CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
481 Length = RawLength - SegOffset;
482 if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
484 memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, Length);
486 else if (CacheSegOffset >= PAGE_SIZE)
488 memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, PAGE_SIZE);
492 memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, CacheSegOffset);
493 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
494 Status = CcRosGetCacheSegment(Bcb,
495 FileOffset + CacheSegOffset,
500 if (!NT_SUCCESS(Status))
502 ExUnmapPage(PageAddr);
508 * If the cache segment isn't up to date then call the file
509 * system to read in the data.
511 Status = ReadCacheSegment(CacheSeg);
512 if (!NT_SUCCESS(Status))
514 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
515 ExUnmapPage(PageAddr);
519 if (Length < PAGE_SIZE)
521 memcpy(PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset);
525 memcpy(PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset);
528 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
529 ExUnmapPage(PageAddr);
531 return(STATUS_SUCCESS);
535 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
536 MEMORY_AREA* MemoryArea,
544 PSECTION_OBJECT Section;
545 PMM_SECTION_SEGMENT Segment;
551 LARGE_INTEGER Timeout;
554 * There is a window between taking the page fault and locking the
555 * address space when another thread could load the page so we check
558 if (MmIsPagePresent(AddressSpace->Process, Address))
562 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace->Process, Address));
564 return(STATUS_SUCCESS);
567 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
568 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
570 Segment = MemoryArea->Data.SectionData.Segment;
571 Section = MemoryArea->Data.SectionData.Section;
572 Region = MmFindRegion(MemoryArea->BaseAddress,
573 &MemoryArea->Data.SectionData.RegionListHead,
578 MmLockSectionSegment(Segment);
581 * Check if this page needs to be mapped COW
583 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
584 (Region->Protect == PAGE_READWRITE ||
585 Region->Protect == PAGE_EXECUTE_READWRITE))
587 Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ;
591 Attributes = Region->Protect;
595 * Get or create a page operation descriptor
597 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN);
600 DPRINT1("MmGetPageOp failed\n");
605 * Check if someone else is already handling this fault, if so wait
608 if (PageOp->Thread != PsGetCurrentThread())
610 MmUnlockSectionSegment(Segment);
611 MmUnlockAddressSpace(AddressSpace);
612 Timeout.QuadPart = -100000000LL; // 10 sec
613 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
620 * Check for various strange conditions
622 if (Status != STATUS_SUCCESS)
624 DPRINT1("Failed to wait for page op, status = %x\n", Status);
627 if (PageOp->Status == STATUS_PENDING)
629 DPRINT1("Woke for page op before completion\n");
632 MmLockAddressSpace(AddressSpace);
634 * If this wasn't a pagein then restart the operation
636 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
638 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
639 MmReleasePageOp(PageOp);
640 DPRINT("Address 0x%.8X\n", Address);
641 return(STATUS_MM_RESTART_OPERATION);
645 * If the thread handling this fault has failed then we don't retry
647 if (!NT_SUCCESS(PageOp->Status))
649 Status = PageOp->Status;
650 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
651 MmReleasePageOp(PageOp);
652 DPRINT("Address 0x%.8X\n", Address);
655 MmLockSectionSegment(Segment);
657 * If the completed fault was for another address space then set the
660 if (!MmIsPagePresent(AddressSpace->Process, Address))
662 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
665 MmUnlockSectionSegment(Segment);
666 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
667 MmReleasePageOp(PageOp);
668 return(STATUS_MM_RESTART_OPERATION);
671 Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry));
672 MmReferencePage(Page);
673 MmSharePageEntrySectionSegment(Segment, Offset);
675 Status = MmCreateVirtualMapping(MemoryArea->Process,
680 if (Status == STATUS_NO_MEMORY)
682 MmUnlockAddressSpace(AddressSpace);
683 Status = MmCreateVirtualMapping(MemoryArea->Process,
688 MmLockAddressSpace(AddressSpace);
691 if (!NT_SUCCESS(Status))
693 DbgPrint("Unable to create virtual mapping\n");
696 MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress);
702 MmUnlockSectionSegment(Segment);
703 PageOp->Status = STATUS_SUCCESS;
704 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
705 MmReleasePageOp(PageOp);
706 DPRINT("Address 0x%.8X\n", Address);
707 return(STATUS_SUCCESS);
711 * Must be private page we have swapped out.
713 if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress))
721 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
723 DPRINT1("Found a swaped out private page in a pagefile section.\n");
727 MmUnlockSectionSegment(Segment);
728 MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry);
730 MmUnlockAddressSpace(AddressSpace);
731 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
732 if (!NT_SUCCESS(Status))
737 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
738 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
739 Status = MmReadFromSwapPage(SwapEntry, Mdl);
740 if (!NT_SUCCESS(Status))
742 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
745 MmLockAddressSpace(AddressSpace);
746 Status = MmCreateVirtualMapping(AddressSpace->Process,
751 if (Status == STATUS_NO_MEMORY)
753 MmUnlockAddressSpace(AddressSpace);
754 Status = MmCreateVirtualMapping(AddressSpace->Process,
759 MmLockAddressSpace(AddressSpace);
761 if (!NT_SUCCESS(Status))
763 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
769 * Store the swap entry for later use.
771 MmSetSavedSwapEntryPage(Page, SwapEntry);
774 * Add the page to the process's working set
776 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
779 * Finish the operation
783 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
785 PageOp->Status = STATUS_SUCCESS;
786 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
787 MmReleasePageOp(PageOp);
788 DPRINT("Address 0x%.8X\n", Address);
789 return(STATUS_SUCCESS);
793 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
795 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
797 MmUnlockSectionSegment(Segment);
799 * Just map the desired physical page
801 Page.QuadPart = Offset + MemoryArea->Data.SectionData.ViewOffset;
802 Status = MmCreateVirtualMapping(AddressSpace->Process,
807 if (Status == STATUS_NO_MEMORY)
809 MmUnlockAddressSpace(AddressSpace);
810 Status = MmCreateVirtualMapping(AddressSpace->Process,
815 MmLockAddressSpace(AddressSpace);
817 if (!NT_SUCCESS(Status))
819 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
824 * Don't add an rmap entry since the page mapped could be for
833 * Cleanup and release locks
835 PageOp->Status = STATUS_SUCCESS;
836 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
837 MmReleasePageOp(PageOp);
838 DPRINT("Address 0x%.8X\n", Address);
839 return(STATUS_SUCCESS);
843 * Map anonymous memory for BSS sections
845 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
847 MmUnlockSectionSegment(Segment);
848 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
849 if (!NT_SUCCESS(Status))
851 MmUnlockAddressSpace(AddressSpace);
852 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
853 MmLockAddressSpace(AddressSpace);
855 if (!NT_SUCCESS(Status))
859 Status = MmCreateVirtualMapping(AddressSpace->Process,
864 if (Status == STATUS_NO_MEMORY)
866 MmUnlockAddressSpace(AddressSpace);
867 Status = MmCreateVirtualMapping(AddressSpace->Process,
872 MmLockAddressSpace(AddressSpace);
875 if (!NT_SUCCESS(Status))
877 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
881 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
888 * Cleanup and release locks
890 PageOp->Status = STATUS_SUCCESS;
891 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
892 MmReleasePageOp(PageOp);
893 DPRINT("Address 0x%.8X\n", Address);
894 return(STATUS_SUCCESS);
898 * Get the entry corresponding to the offset within the section
900 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
905 * If the entry is zero (and it can't change because we have
906 * locked the segment) then we need to load the page.
910 * Release all our locks and read in the page from disk
912 MmUnlockSectionSegment(Segment);
913 MmUnlockAddressSpace(AddressSpace);
915 if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
916 (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE))
918 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
919 if (!NT_SUCCESS(Status))
921 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
926 Status = MiReadPage(MemoryArea, Offset, &Page);
927 if (!NT_SUCCESS(Status))
929 DPRINT1("MiReadPage failed (Status %x)\n", Status);
932 if (!NT_SUCCESS(Status))
935 * FIXME: What do we know in this case?
938 * Cleanup and release locks
940 MmLockAddressSpace(AddressSpace);
941 PageOp->Status = Status;
942 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
943 MmReleasePageOp(PageOp);
944 DPRINT("Address 0x%.8X\n", Address);
948 * Relock the address space and segment
950 MmLockAddressSpace(AddressSpace);
951 MmLockSectionSegment(Segment);
954 * Check the entry. No one should change the status of a page
955 * that has a pending page-in.
957 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
960 DbgPrint("Someone changed ppte entry while we slept\n");
965 * Mark the offset within the section as having valid, in-memory
968 Entry = MAKE_SSE(Page.u.LowPart, 1);
969 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
970 MmUnlockSectionSegment(Segment);
972 Status = MmCreateVirtualMapping(AddressSpace->Process,
977 if (Status == STATUS_NO_MEMORY)
979 MmUnlockAddressSpace(AddressSpace);
980 Status = MmCreateVirtualMapping(AddressSpace->Process,
985 MmLockAddressSpace(AddressSpace);
987 if (!NT_SUCCESS(Status))
989 DbgPrint("Unable to create virtual mapping\n");
992 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
998 PageOp->Status = STATUS_SUCCESS;
999 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1000 MmReleasePageOp(PageOp);
1001 DPRINT("Address 0x%.8X\n", Address);
1002 return(STATUS_SUCCESS);
1004 else if (IS_SWAP_FROM_SSE(Entry))
1006 SWAPENTRY SwapEntry;
1009 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
1012 * Release all our locks and read in the page from disk
1014 MmUnlockSectionSegment(Segment);
1016 MmUnlockAddressSpace(AddressSpace);
1018 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
1019 if (!NT_SUCCESS(Status))
1024 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1025 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
1026 Status = MmReadFromSwapPage(SwapEntry, Mdl);
1027 if (!NT_SUCCESS(Status))
1033 * Relock the address space and segment
1035 MmLockAddressSpace(AddressSpace);
1036 MmLockSectionSegment(Segment);
1039 * Check the entry. No one should change the status of a page
1040 * that has a pending page-in.
1042 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset);
1043 if (Entry != Entry1)
1045 DbgPrint("Someone changed ppte entry while we slept\n");
1050 * Mark the offset within the section as having valid, in-memory
1053 Entry = MAKE_SSE(Page.u.LowPart, 1);
1054 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
1055 MmUnlockSectionSegment(Segment);
1058 * Save the swap entry.
1060 MmSetSavedSwapEntryPage(Page, SwapEntry);
1061 Status = MmCreateVirtualMapping(AddressSpace->Process,
1066 if (Status == STATUS_NO_MEMORY)
1068 MmUnlockAddressSpace(AddressSpace);
1069 Status = MmCreateVirtualMapping(AddressSpace->Process,
1074 MmLockAddressSpace(AddressSpace);
1076 if (!NT_SUCCESS(Status))
1078 DbgPrint("Unable to create virtual mapping\n");
1081 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1086 PageOp->Status = STATUS_SUCCESS;
1087 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1088 MmReleasePageOp(PageOp);
1089 DPRINT("Address 0x%.8X\n", Address);
1090 return(STATUS_SUCCESS);
1095 * If the section offset is already in-memory and valid then just
1096 * take another reference to the page
1099 Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry);
1100 MmReferencePage(Page);
1101 MmSharePageEntrySectionSegment(Segment, Offset);
1102 MmUnlockSectionSegment(Segment);
1104 Status = MmCreateVirtualMapping(AddressSpace->Process,
1109 if (Status == STATUS_NO_MEMORY)
1111 MmUnlockAddressSpace(AddressSpace);
1112 Status = MmCreateVirtualMapping(AddressSpace->Process,
1117 MmLockAddressSpace(AddressSpace);
1119 if (!NT_SUCCESS(Status))
1121 DbgPrint("Unable to create virtual mapping\n");
1124 MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress);
1129 PageOp->Status = STATUS_SUCCESS;
1130 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1131 MmReleasePageOp(PageOp);
1132 DPRINT("Address 0x%.8X\n", Address);
1133 return(STATUS_SUCCESS);
1138 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1139 MEMORY_AREA* MemoryArea,
1143 PMM_SECTION_SEGMENT Segment;
1144 PSECTION_OBJECT Section;
1145 PHYSICAL_ADDRESS OldPage;
1146 PHYSICAL_ADDRESS NewPage;
1153 LARGE_INTEGER Timeout;
1156 * Check if the page has been paged out or has already been set readwrite
1158 if (!MmIsPagePresent(AddressSpace->Process, Address) ||
1159 MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE)
1161 DPRINT("Address 0x%.8X\n", Address);
1162 return(STATUS_SUCCESS);
1166 * Find the offset of the page
1168 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
1169 Offset = PAddress - (ULONG)MemoryArea->BaseAddress;
1171 Segment = MemoryArea->Data.SectionData.Segment;
1172 Section = MemoryArea->Data.SectionData.Section;
1173 Region = MmFindRegion(MemoryArea->BaseAddress,
1174 &MemoryArea->Data.SectionData.RegionListHead,
1179 MmLockSectionSegment(Segment);
1184 if (MmGetPageEntrySectionSegment(Segment, Offset) == 0)
1186 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1189 MmUnlockSectionSegment(Segment);
1191 * Check if we are doing COW
1193 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1194 (Region->Protect == PAGE_READWRITE ||
1195 Region->Protect == PAGE_EXECUTE_READWRITE)))
1197 DPRINT("Address 0x%.8X\n", Address);
1198 return(STATUS_UNSUCCESSFUL);
1202 * Get or create a pageop
1204 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset,
1205 MM_PAGEOP_ACCESSFAULT);
1208 DPRINT1("MmGetPageOp failed\n");
1213 * Wait for any other operations to complete
1215 if (PageOp->Thread != PsGetCurrentThread())
1217 MmUnlockAddressSpace(AddressSpace);
1218 Timeout.QuadPart = -100000000LL; // 10 sec
1219 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
1225 * Check for various strange conditions
1227 if (Status == STATUS_TIMEOUT)
1229 DPRINT1("Failed to wait for page op, status = %x\n", Status);
1232 if (PageOp->Status == STATUS_PENDING)
1234 DPRINT1("Woke for page op before completion\n");
1238 * Restart the operation
1240 MmLockAddressSpace(AddressSpace);
1241 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1242 MmReleasePageOp(PageOp);
1243 DPRINT("Address 0x%.8X\n", Address);
1244 return(STATUS_MM_RESTART_OPERATION);
1248 * Release locks now we have the pageop
1250 MmUnlockAddressSpace(AddressSpace);
1255 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1256 if (!NT_SUCCESS(Status))
1264 OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
1266 NewAddress = ExAllocatePageWithPhysPage(NewPage);
1267 memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE);
1268 ExUnmapPage(NewAddress);
1271 * Delete the old entry.
1273 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
1276 * Set the PTE to point to the new page
1278 MmLockAddressSpace(AddressSpace);
1279 Status = MmCreateVirtualMapping(AddressSpace->Process,
1284 if (Status == STATUS_NO_MEMORY)
1286 MmUnlockAddressSpace(AddressSpace);
1287 Status = MmCreateVirtualMapping(AddressSpace->Process,
1292 MmLockAddressSpace(AddressSpace);
1294 if (!NT_SUCCESS(Status))
1296 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1300 MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress);
1301 if (!NT_SUCCESS(Status))
1303 DbgPrint("Unable to create virtual mapping\n");
1308 MmLockPage(NewPage);
1312 * Unshare the old page.
1314 MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress);
1315 MmLockSectionSegment(Segment);
1316 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE);
1317 MmUnlockSectionSegment(Segment);
1318 MmReleasePageMemoryConsumer(MC_USER, OldPage);
1320 PageOp->Status = STATUS_SUCCESS;
1321 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1322 MmReleasePageOp(PageOp);
1323 DPRINT("Address 0x%.8X\n", Address);
1324 return(STATUS_SUCCESS);
1328 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1330 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1332 PHYSICAL_ADDRESS Page;
1334 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1335 MmDeleteVirtualMapping(Process,
1342 PageOutContext->WasDirty = TRUE;
1344 if (!PageOutContext->Private)
1346 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1347 PageOutContext->Segment,
1348 PageOutContext->Offset,
1349 PageOutContext->WasDirty);
1351 MmReleasePageMemoryConsumer(MC_USER, Page);
1352 DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address);
1356 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1357 MEMORY_AREA* MemoryArea,
1361 PHYSICAL_ADDRESS PhysicalAddress;
1362 MM_SECTION_PAGEOUT_CONTEXT Context;
1363 SWAPENTRY SwapEntry;
1368 PFILE_OBJECT FileObject;
1370 BOOLEAN DirectMapped;
1371 BOOLEAN IsImageSection;
1373 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1376 * Get the segment and section.
1378 Context.Segment = MemoryArea->Data.SectionData.Segment;
1379 Context.Section = MemoryArea->Data.SectionData.Section;
1381 Context.Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
1382 FileOffset = Context.Offset + Context.Segment->FileOffset;
1384 IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1386 FileObject = Context.Section->FileObject;
1387 DirectMapped = FALSE;
1388 if (FileObject != NULL)
1390 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1393 * If the file system is letting us go directly to the cache and the
1394 * memory area was mapped at an offset in the file which is page aligned
1395 * then note this is a direct mapped page.
1397 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1398 (FileOffset % PAGE_SIZE) == 0 &&
1399 (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection))
1401 DirectMapped = TRUE;
1407 * This should never happen since mappings of physical memory are never
1408 * placed in the rmap lists.
1410 if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1412 DPRINT1("Trying to page out from physical memory section address 0x%X "
1413 "process %d\n", Address,
1414 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1419 * Get the section segment entry and the physical address.
1421 Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset);
1422 if (!MmIsPagePresent(AddressSpace->Process, Address))
1424 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1425 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1429 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1430 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1433 * Prepare the context structure for the rmap delete call.
1435 Context.WasDirty = FALSE;
1436 if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1437 IS_SWAP_FROM_SSE(Entry) ||
1438 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1440 Context.Private = TRUE;
1444 Context.Private = FALSE;
1448 * Paging out data mapped read-only is easy.
1450 if (Context.Segment->Protection & (PAGE_READONLY|PAGE_EXECUTE_READ))
1453 * Read-only data should never be in the swapfile.
1457 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1458 "paddress 0x%.8X\n", SwapEntry, Address,
1464 * Read-only data should never be COWed
1466 if (Context.Private)
1468 DPRINT1("Had private copy of read-only page.\n");
1473 * Delete all mappings of this page.
1475 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context,
1476 MmPageOutDeleteMapping);
1477 if (Context.WasDirty)
1479 DPRINT1("Had a dirty page of a read-only page.\n");
1483 PageOp->Status = STATUS_SUCCESS;
1484 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1485 MmReleasePageOp(PageOp);
1486 return(STATUS_SUCCESS);
1490 * Otherwise we have read-write data.
1494 * Take an additional reference to the page or the cache segment.
1496 if (DirectMapped && !Context.Private)
1498 if(!MiIsPageFromCache(MemoryArea, Context.Offset))
1500 DPRINT1("Direct mapped non private page is not associated with the cache.\n")
1506 MmReferencePage(PhysicalAddress);
1509 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
1512 * If this wasn't a private page then we should have reduced the entry to
1513 * zero by deleting all the rmaps.
1515 if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0)
1517 if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT))
1525 * If the page wasn't dirty then we can just free it as for a readonly page.
1526 * Since we unmapped all the mappings above we know it will not suddenly
1528 * If the page is from a pagefile section and has no swap entry,
1529 * we can't free the page at this point.
1531 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1532 if (!Context.WasDirty &&
1533 !(SwapEntry == 0 && Context.Segment->Flags & MM_PAGEFILE_SEGMENT))
1536 if (Context.Private)
1538 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1539 if (!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
1542 DPRINT1("Private page, non-dirty but not swapped out "
1543 "process %d address 0x%.8X\n",
1544 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0,
1550 Status = MmCreatePageFileMapping(AddressSpace->Process,
1553 if (!NT_SUCCESS(Status))
1559 if (DirectMapped && !Context.Private)
1561 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1562 if (!NT_SUCCESS(Status))
1564 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
1570 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1573 PageOp->Status = STATUS_SUCCESS;
1574 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1575 MmReleasePageOp(PageOp);
1576 return(STATUS_SUCCESS);
1580 * If this page was direct mapped from the cache then the cache manager
1581 * will already have taken care of writing it back.
1583 if (DirectMapped && !Context.Private)
1585 assert(SwapEntry == 0);
1586 Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
1587 if (!NT_SUCCESS(Status))
1589 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
1592 PageOp->Status = STATUS_SUCCESS;
1593 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1594 MmReleasePageOp(PageOp);
1595 return(STATUS_SUCCESS);
1599 * If necessary, allocate an entry in the paging file for this page
1603 SwapEntry = MmAllocSwapPage();
1606 MmShowOutOfSpaceMessagePagingFile();
1609 * For private pages restore the old mappings.
1611 if (Context.Private)
1613 Status = MmCreateVirtualMapping(MemoryArea->Process,
1615 MemoryArea->Attributes,
1618 MmSetDirtyPage(MemoryArea->Process, Address);
1619 MmInsertRmap(PhysicalAddress,
1620 MemoryArea->Process,
1626 * For non-private pages if the page wasn't direct mapped then
1627 * set it back into the section segment entry so we don't loose
1628 * our copy. Otherwise it will be handled by the cache manager.
1630 Status = MmCreateVirtualMapping(MemoryArea->Process,
1632 MemoryArea->Attributes,
1635 MmSetDirtyPage(MemoryArea->Process, Address);
1636 MmInsertRmap(PhysicalAddress,
1637 MemoryArea->Process,
1639 Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1);
1640 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1642 PageOp->Status = STATUS_UNSUCCESSFUL;
1643 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1644 MmReleasePageOp(PageOp);
1645 return(STATUS_PAGEFILE_QUOTA);
1650 * Write the page to the pagefile
1652 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1653 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1654 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1655 if (!NT_SUCCESS(Status))
1657 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1660 * As above: undo our actions.
1661 * FIXME: Also free the swap page.
1663 if (Context.Private)
1665 Status = MmCreateVirtualMapping(MemoryArea->Process,
1667 MemoryArea->Attributes,
1670 MmSetDirtyPage(MemoryArea->Process, Address);
1671 MmInsertRmap(PhysicalAddress,
1672 MemoryArea->Process,
1677 Status = MmCreateVirtualMapping(MemoryArea->Process,
1679 MemoryArea->Attributes,
1682 MmSetDirtyPage(MemoryArea->Process, Address);
1683 MmInsertRmap(PhysicalAddress,
1684 MemoryArea->Process,
1686 Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1);
1687 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1689 PageOp->Status = STATUS_UNSUCCESSFUL;
1690 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1691 MmReleasePageOp(PageOp);
1692 return(STATUS_UNSUCCESSFUL);
1696 * Otherwise we have succeeded.
1698 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1699 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1700 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1702 if (Context.Private)
1704 Status = MmCreatePageFileMapping(MemoryArea->Process,
1707 if (!NT_SUCCESS(Status))
1714 Entry = MAKE_SWAP_SSE(SwapEntry);
1715 MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry);
1718 PageOp->Status = STATUS_SUCCESS;
1719 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1720 MmReleasePageOp(PageOp);
1721 return(STATUS_SUCCESS);
1725 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1726 PMEMORY_AREA MemoryArea,
1731 PSECTION_OBJECT Section;
1732 PMM_SECTION_SEGMENT Segment;
1733 PHYSICAL_ADDRESS PhysicalAddress;
1734 SWAPENTRY SwapEntry;
1739 PFILE_OBJECT FileObject;
1741 BOOLEAN DirectMapped;
1742 BOOLEAN IsImageSection;
1744 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1746 Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
1749 * Get the segment and section.
1751 Segment = MemoryArea->Data.SectionData.Segment;
1752 Section = MemoryArea->Data.SectionData.Section;
1753 IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
1755 FileObject = Section->FileObject;
1756 DirectMapped = FALSE;
1757 if (FileObject != NULL)
1759 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
1762 * If the file system is letting us go directly to the cache and the
1763 * memory area was mapped at an offset in the file which is page aligned
1764 * then note this is a direct mapped page.
1766 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1767 (Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 &&
1768 (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection))
1770 DirectMapped = TRUE;
1775 * This should never happen since mappings of physical memory are never
1776 * placed in the rmap lists.
1778 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1780 DPRINT1("Trying to write back page from physical memory mapped at %X "
1781 "process %d\n", Address,
1782 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0);
1787 * Get the section segment entry and the physical address.
1789 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1790 if (!MmIsPagePresent(AddressSpace->Process, Address))
1792 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1793 AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address);
1797 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1798 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1801 * Check for a private (COWed) page.
1803 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1804 IS_SWAP_FROM_SSE(Entry) ||
1805 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1815 * Speculatively set all mappings of the page to clean.
1817 MmSetCleanAllRmaps(PhysicalAddress);
1820 * If this page was direct mapped from the cache then the cache manager
1821 * will take care of writing it back to disk.
1823 if (DirectMapped && !Private)
1825 assert(SwapEntry == 0);
1826 CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset);
1827 PageOp->Status = STATUS_SUCCESS;
1828 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1829 MmReleasePageOp(PageOp);
1830 return(STATUS_SUCCESS);
1834 * If necessary, allocate an entry in the paging file for this page
1838 SwapEntry = MmAllocSwapPage();
1841 MmSetDirtyAllRmaps(PhysicalAddress);
1842 PageOp->Status = STATUS_UNSUCCESSFUL;
1843 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1844 MmReleasePageOp(PageOp);
1845 return(STATUS_PAGEFILE_QUOTA);
1850 * Write the page to the pagefile
1852 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1853 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1854 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1855 if (!NT_SUCCESS(Status))
1857 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1859 MmSetDirtyAllRmaps(PhysicalAddress);
1860 PageOp->Status = STATUS_UNSUCCESSFUL;
1861 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1862 MmReleasePageOp(PageOp);
1863 return(STATUS_UNSUCCESSFUL);
1867 * Otherwise we have succeeded.
1869 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1870 MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
1871 PageOp->Status = STATUS_SUCCESS;
1872 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1873 MmReleasePageOp(PageOp);
1874 return(STATUS_SUCCESS);
1878 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1886 PMEMORY_AREA MemoryArea;
1887 PMM_SECTION_SEGMENT Segment;
1891 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1892 Segment = MemoryArea->Data.SectionData.Segment;
1894 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1895 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1900 if (OldProtect != NewProtect)
1902 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1904 PVOID Address = BaseAddress + (i * PAGE_SIZE);
1905 ULONG Protect = NewProtect;
1908 * If we doing COW for this segment then check if the page is
1911 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1915 LARGE_INTEGER PhysicalAddress;
1917 Offset = (ULONG)Address - (ULONG)MemoryArea->BaseAddress;
1918 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
1920 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1922 Protect = PAGE_READONLY;
1923 if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1924 IS_SWAP_FROM_SSE(Entry) ||
1925 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart))
1927 Protect = NewProtect;
1931 if (MmIsPagePresent(AddressSpace->Process, Address))
1933 MmSetPageProtect(AddressSpace->Process, BaseAddress,
1941 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1942 PMEMORY_AREA MemoryArea,
1952 min(Length, (ULONG) (MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress));
1953 Region = MmFindRegion(MemoryArea->BaseAddress,
1954 &MemoryArea->Data.SectionData.RegionListHead,
1956 *OldProtect = Region->Protect;
1957 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1958 &MemoryArea->Data.SectionData.RegionListHead,
1959 BaseAddress, Length, Region->Type, Protect,
1960 MmAlterViewAttributes);
1966 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1968 PMEMORY_BASIC_INFORMATION Info,
1969 PULONG ResultLength)
1972 PVOID RegionBaseAddress;
1974 Region = MmFindRegion(MemoryArea->BaseAddress,
1975 &MemoryArea->Data.SectionData.RegionListHead,
1976 Address, &RegionBaseAddress);
1979 return STATUS_UNSUCCESSFUL;
1981 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
1982 Info->AllocationBase = MemoryArea->BaseAddress;
1983 Info->AllocationProtect = MemoryArea->Attributes;
1984 Info->RegionSize = MemoryArea->Length;
1985 Info->State = MEM_COMMIT;
1986 Info->Protect = Region->Protect;
1987 if (MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE)
1989 Info->Type = MEM_IMAGE;
1993 Info->Type = MEM_MAPPED;
1996 return(STATUS_SUCCESS);
2000 MmpDeleteSection(PVOID ObjectBody)
2002 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
2004 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
2005 if (Section->AllocationAttributes & SEC_IMAGE)
2009 PMM_SECTION_SEGMENT SectionSegments;
2011 SectionSegments = Section->ImageSection->Segments;
2012 NrSegments = Section->ImageSection->NrSegments;
2014 for (i = 0; i < NrSegments; i++)
2016 InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount);
2021 if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT)
2026 PMM_SECTION_SEGMENT Segment;
2028 Segment = Section->Segment;
2029 Length = PAGE_ROUND_UP(Segment->Length);
2031 for (Offset = 0; Offset < Length; Offset += PAGE_SIZE)
2033 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
2036 if (IS_SWAP_FROM_SSE(Entry))
2038 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
2042 PHYSICAL_ADDRESS Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
2043 MmReleasePageMemoryConsumer(MC_USER, Page);
2047 MmFreePageTablesSectionSegment(Section->Segment);
2048 ExFreePool(Section->Segment);
2049 Section->Segment = NULL;
2053 InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount);
2056 if (Section->FileObject != NULL)
2058 CcRosDereferenceCache(Section->FileObject);
2059 ObDereferenceObject(Section->FileObject);
2060 Section->FileObject = NULL;
2065 MmpCloseSection(PVOID ObjectBody,
2068 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2069 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
2073 MmpCreateSection(PVOID ObjectBody,
2075 PWSTR RemainingPath,
2076 POBJECT_ATTRIBUTES ObjectAttributes)
2078 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2079 ObjectBody, Parent, RemainingPath);
2081 if (RemainingPath == NULL)
2083 return(STATUS_SUCCESS);
2086 if (wcschr(RemainingPath+1, L'\\') != NULL)
2088 return(STATUS_UNSUCCESSFUL);
2090 return(STATUS_SUCCESS);
2094 MmCreatePhysicalMemorySection(VOID)
2096 HANDLE PhysSectionH;
2097 PSECTION_OBJECT PhysSection;
2099 OBJECT_ATTRIBUTES Obj;
2100 UNICODE_STRING Name = UNICODE_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
2101 LARGE_INTEGER SectionSize;
2104 * Create the section mapping physical memory
2106 SectionSize.QuadPart = 0xFFFFFFFF;
2107 InitializeObjectAttributes(&Obj,
2112 Status = NtCreateSection(&PhysSectionH,
2116 PAGE_EXECUTE_READWRITE,
2119 if (!NT_SUCCESS(Status))
2121 DbgPrint("Failed to create PhysicalMemory section\n");
2124 Status = ObReferenceObjectByHandle(PhysSectionH,
2128 (PVOID*)&PhysSection,
2130 if (!NT_SUCCESS(Status))
2132 DbgPrint("Failed to reference PhysicalMemory section\n");
2135 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
2136 ObDereferenceObject((PVOID)PhysSection);
2138 return(STATUS_SUCCESS);
2142 MmInitSectionImplementation(VOID)
2144 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
2146 RtlInitUnicodeStringFromLiteral(&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;
2167 return(STATUS_SUCCESS);
2171 MmCreatePageFileSection(PHANDLE SectionHandle,
2172 ACCESS_MASK DesiredAccess,
2173 POBJECT_ATTRIBUTES ObjectAttributes,
2174 PLARGE_INTEGER UMaximumSize,
2175 ULONG SectionPageProtection,
2176 ULONG AllocationAttributes)
2178 * Create a section which is backed by the pagefile
2181 LARGE_INTEGER MaximumSize;
2182 PSECTION_OBJECT Section;
2183 PMM_SECTION_SEGMENT Segment;
2186 if (UMaximumSize == NULL)
2188 return(STATUS_UNSUCCESSFUL);
2190 MaximumSize = *UMaximumSize;
2193 * Check the protection
2195 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2196 SectionPageProtection)
2198 return(STATUS_INVALID_PAGE_PROTECTION);
2202 * Create the section
2204 Status = ObRosCreateObject(SectionHandle,
2207 MmSectionObjectType,
2209 if (!NT_SUCCESS(Status))
2217 Section->SectionPageProtection = SectionPageProtection;
2218 Section->AllocationAttributes = AllocationAttributes;
2219 InitializeListHead(&Section->ViewListHead);
2220 KeInitializeSpinLock(&Section->ViewListLock);
2221 Section->FileObject = NULL;
2222 Section->MaximumSize = MaximumSize;
2223 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2224 TAG_MM_SECTION_SEGMENT);
2225 if (Segment == NULL)
2227 ZwClose(*SectionHandle);
2228 ObDereferenceObject(Section);
2229 return(STATUS_NO_MEMORY);
2231 Section->Segment = Segment;
2232 Segment->ReferenceCount = 1;
2233 ExInitializeFastMutex(&Segment->Lock);
2234 Segment->FileOffset = 0;
2235 Segment->Protection = SectionPageProtection;
2236 Segment->Attributes = AllocationAttributes;
2237 Segment->Length = MaximumSize.u.LowPart;
2238 Segment->Flags = MM_PAGEFILE_SEGMENT;
2239 Segment->WriteCopy = FALSE;
2240 ObDereferenceObject(Section);
2241 return(STATUS_SUCCESS);
2246 MmCreateDataFileSection(PHANDLE SectionHandle,
2247 ACCESS_MASK DesiredAccess,
2248 POBJECT_ATTRIBUTES ObjectAttributes,
2249 PLARGE_INTEGER UMaximumSize,
2250 ULONG SectionPageProtection,
2251 ULONG AllocationAttributes,
2254 * Create a section backed by a data file
2257 PSECTION_OBJECT Section;
2259 LARGE_INTEGER MaximumSize;
2260 PFILE_OBJECT FileObject;
2261 PMM_SECTION_SEGMENT Segment;
2263 IO_STATUS_BLOCK Iosb;
2264 LARGE_INTEGER Offset;
2268 * Check the protection
2270 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2271 SectionPageProtection)
2273 return(STATUS_INVALID_PAGE_PROTECTION);
2277 * Read a bit so caching is initiated for the file object.
2278 * This is only needed because MiReadPage currently cannot
2279 * handle non-cached streams.
2281 Offset.QuadPart = 0;
2282 Status = ZwReadFile(FileHandle,
2291 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
2297 * Create the section
2299 Status = ObRosCreateObject(SectionHandle,
2302 MmSectionObjectType,
2304 if (!NT_SUCCESS(Status))
2312 Section->SectionPageProtection = SectionPageProtection;
2313 Section->AllocationAttributes = AllocationAttributes;
2314 InitializeListHead(&Section->ViewListHead);
2315 KeInitializeSpinLock(&Section->ViewListLock);
2318 * Check file access required
2320 if (SectionPageProtection & PAGE_READWRITE ||
2321 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2323 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2327 FileAccess = FILE_READ_DATA;
2331 * Reference the file handle
2333 Status = ObReferenceObjectByHandle(FileHandle,
2337 (PVOID*)&FileObject,
2339 if (!NT_SUCCESS(Status))
2341 ZwClose(*SectionHandle);
2342 ObDereferenceObject(Section);
2347 * We can't do memory mappings if the file system doesn't support the
2350 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2352 ZwClose(*SectionHandle);
2353 ObDereferenceObject(Section);
2354 ObDereferenceObject(FileObject);
2355 return(STATUS_INVALID_FILE_FOR_SECTION);
2359 * FIXME: Revise this once a locking order for file size changes is
2362 if (UMaximumSize != NULL)
2364 MaximumSize = *UMaximumSize;
2369 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
2372 if (MaximumSize.QuadPart >
2373 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
2375 IO_STATUS_BLOCK Iosb;
2376 Status = NtSetInformationFile(FileHandle,
2379 sizeof(LARGE_INTEGER),
2380 FileAllocationInformation);
2381 if (!NT_SUCCESS(Status))
2383 ZwClose(*SectionHandle);
2384 ObDereferenceObject(Section);
2385 ObDereferenceObject(FileObject);
2386 return(STATUS_SECTION_NOT_EXTENDED);
2393 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2398 if (Status != STATUS_SUCCESS)
2400 ZwClose(*SectionHandle);
2401 ObDereferenceObject(Section);
2402 ObDereferenceObject(FileObject);
2407 * If this file hasn't been mapped as a data file before then allocate a
2408 * section segment to describe the data file mapping
2410 if (FileObject->SectionObjectPointer->DataSectionObject == NULL)
2412 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2413 TAG_MM_SECTION_SEGMENT);
2414 if (Segment == NULL)
2416 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2417 ZwClose(*SectionHandle);
2418 ObDereferenceObject(Section);
2419 ObDereferenceObject(FileObject);
2420 return(STATUS_NO_MEMORY);
2422 Section->Segment = Segment;
2423 Segment->ReferenceCount = 1;
2424 ExInitializeFastMutex(&Segment->Lock);
2426 * Set the lock before assigning the segment to the file object
2428 ExAcquireFastMutex(&Segment->Lock);
2429 FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment;
2431 Segment->FileOffset = 0;
2432 Segment->Protection = 0;
2433 Segment->Attributes = 0;
2434 Segment->Flags = MM_DATAFILE_SEGMENT;
2435 Segment->Characteristics = 0;
2436 Segment->WriteCopy = FALSE;
2437 if (AllocationAttributes & SEC_RESERVE)
2439 Segment->Length = Segment->RawLength = 0;
2443 Segment->RawLength = MaximumSize.u.LowPart;
2444 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2446 Segment->VirtualAddress = NULL;
2451 * If the file is already mapped as a data file then we may need
2455 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer->
2457 Section->Segment = Segment;
2458 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2459 MmLockSectionSegment(Segment);
2461 if (MaximumSize.u.LowPart > Segment->RawLength &&
2462 !(AllocationAttributes & SEC_RESERVE))
2464 Segment->RawLength = MaximumSize.u.LowPart;
2465 Segment->Length = PAGE_ROUND_UP(Segment->RawLength);
2468 MmUnlockSectionSegment(Segment);
2469 Section->FileObject = FileObject;
2470 Section->MaximumSize = MaximumSize;
2471 CcRosReferenceCache(FileObject);
2472 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2473 ObDereferenceObject(Section);
2474 return(STATUS_SUCCESS);
2477 static ULONG SectionCharacteristicsToProtect[16] =
2479 PAGE_NOACCESS, // 0 = NONE
2480 PAGE_NOACCESS, // 1 = SHARED
2481 PAGE_EXECUTE, // 2 = EXECUTABLE
2482 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
2483 PAGE_READONLY, // 4 = READABLE
2484 PAGE_READONLY, // 5 = READABLE, SHARED
2485 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
2486 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
2487 PAGE_READWRITE, // 8 = WRITABLE
2488 PAGE_READWRITE, // 9 = WRITABLE, SHARED
2489 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
2490 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
2491 PAGE_READWRITE, // 12 = WRITABLE, READABLE
2492 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
2493 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
2494 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2498 MmCreateImageSection(PHANDLE SectionHandle,
2499 ACCESS_MASK DesiredAccess,
2500 POBJECT_ATTRIBUTES ObjectAttributes,
2501 PLARGE_INTEGER UMaximumSize,
2502 ULONG SectionPageProtection,
2503 ULONG AllocationAttributes,
2506 PSECTION_OBJECT Section;
2508 PFILE_OBJECT FileObject;
2509 IMAGE_DOS_HEADER DosHeader;
2510 IO_STATUS_BLOCK Iosb;
2511 LARGE_INTEGER Offset;
2512 IMAGE_NT_HEADERS PEHeader;
2513 PIMAGE_SECTION_HEADER ImageSections;
2514 PMM_SECTION_SEGMENT SectionSegments;
2516 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2519 ULONG Characteristics;
2520 ULONG FileAccess = 0;
2522 * Check the protection
2524 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2525 SectionPageProtection)
2527 return(STATUS_INVALID_PAGE_PROTECTION);
2531 * Specifying a maximum size is meaningless for an image section
2533 if (UMaximumSize != NULL)
2535 return(STATUS_INVALID_PARAMETER_4);
2539 * Reference the file handle
2541 Status = ObReferenceObjectByHandle(FileHandle,
2545 (PVOID*)&FileObject,
2547 if (!NT_SUCCESS(Status))
2553 * Initialized caching for this file object if previously caching
2554 * was initialized for the same on disk file
2556 Status = CcTryToInitializeFileCache(FileObject);
2558 if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
2561 * Read the dos header and check the DOS signature
2563 Offset.QuadPart = 0;
2564 Status = ZwReadFile(FileHandle,
2573 if (!NT_SUCCESS(Status))
2575 ObDereferenceObject(FileObject);
2580 * Check the DOS signature
2582 if (Iosb.Information != sizeof(DosHeader) ||
2583 DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2585 ObDereferenceObject(FileObject);
2586 return(STATUS_INVALID_IMAGE_FORMAT);
2590 * Read the PE header
2592 Offset.QuadPart = DosHeader.e_lfanew;
2593 Status = ZwReadFile(FileHandle,
2602 if (!NT_SUCCESS(Status))
2604 ObDereferenceObject(FileObject);
2609 * Check the signature
2611 if (Iosb.Information != sizeof(PEHeader) ||
2612 PEHeader.Signature != IMAGE_NT_SIGNATURE)
2614 ObDereferenceObject(FileObject);
2615 return(STATUS_INVALID_IMAGE_FORMAT);
2619 * Read in the section headers
2621 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2622 ImageSections = ExAllocatePool(NonPagedPool,
2623 PEHeader.FileHeader.NumberOfSections *
2624 sizeof(IMAGE_SECTION_HEADER));
2625 if (ImageSections == NULL)
2627 ObDereferenceObject(FileObject);
2628 return(STATUS_NO_MEMORY);
2631 Status = ZwReadFile(FileHandle,
2637 PEHeader.FileHeader.NumberOfSections *
2638 sizeof(IMAGE_SECTION_HEADER),
2641 if (!NT_SUCCESS(Status))
2643 ObDereferenceObject(FileObject);
2644 ExFreePool(ImageSections);
2647 if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2649 ObDereferenceObject(FileObject);
2650 ExFreePool(ImageSections);
2651 return(STATUS_INVALID_IMAGE_FORMAT);
2655 * Create the section
2657 Status = ObRosCreateObject(SectionHandle,
2660 MmSectionObjectType,
2662 if (!NT_SUCCESS(Status))
2664 ObDereferenceObject(FileObject);
2665 ExFreePool(ImageSections);
2672 Section->SectionPageProtection = SectionPageProtection;
2673 Section->AllocationAttributes = AllocationAttributes;
2674 InitializeListHead(&Section->ViewListHead);
2675 KeInitializeSpinLock(&Section->ViewListLock);
2678 * Check file access required
2680 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2682 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2686 FileAccess = FILE_READ_DATA;
2690 * We can't do memory mappings if the file system doesn't support the
2693 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2695 ZwClose(*SectionHandle);
2696 ObDereferenceObject(Section);
2697 ObDereferenceObject(FileObject);
2698 ExFreePool(ImageSections);
2699 return(STATUS_INVALID_FILE_FOR_SECTION);
2705 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2710 if (Status != STATUS_SUCCESS)
2712 ZwClose(*SectionHandle);
2713 ObDereferenceObject(Section);
2714 ObDereferenceObject(FileObject);
2715 ExFreePool(ImageSections);
2720 * allocate the section segments to describe the mapping
2722 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2723 Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments;
2724 ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2725 if (ImageSectionObject == NULL)
2727 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2728 ZwClose(*SectionHandle);
2729 ObDereferenceObject(Section);
2730 ObDereferenceObject(FileObject);
2731 ExFreePool(ImageSections);
2732 return(STATUS_NO_MEMORY);
2734 Section->ImageSection = ImageSectionObject;
2735 ImageSectionObject->NrSegments = NrSegments;
2736 ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2737 ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2738 ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2739 ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2740 ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem;
2741 ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion;
2742 ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion;
2743 ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2744 ImageSectionObject->Machine = PEHeader.FileHeader.Machine;
2745 ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2747 SectionSegments = ImageSectionObject->Segments;
2748 SectionSegments[0].FileOffset = 0;
2749 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2750 SectionSegments[0].Protection = PAGE_READONLY;
2751 SectionSegments[0].RawLength = PAGE_SIZE;
2752 SectionSegments[0].Length = PAGE_SIZE;
2753 SectionSegments[0].Flags = 0;
2754 SectionSegments[0].ReferenceCount = 1;
2755 SectionSegments[0].VirtualAddress = 0;
2756 SectionSegments[0].WriteCopy = FALSE;
2757 ExInitializeFastMutex(&SectionSegments[0].Lock);
2758 for (i = 1; i < NrSegments; i++)
2760 SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData;
2761 SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics;
2764 * Set up the protection and write copy variables.
2766 Characteristics = ImageSections[i - 1].Characteristics;
2767 if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE))
2769 SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28];
2770 SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2772 else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2774 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2775 SectionSegments[i].WriteCopy = TRUE;
2777 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2779 SectionSegments[i].Protection = PAGE_READWRITE;
2780 SectionSegments[i].WriteCopy = TRUE;
2782 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2784 SectionSegments[i].Protection = PAGE_READWRITE;
2785 SectionSegments[i].WriteCopy = TRUE;
2789 SectionSegments[i].Protection = PAGE_NOACCESS;
2790 SectionSegments[i].WriteCopy = TRUE;
2794 * Set up the attributes.
2796 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2798 SectionSegments[i].Attributes = 0;
2800 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2802 SectionSegments[i].Attributes = 0;
2804 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2806 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2810 SectionSegments[i].Attributes = 0;
2813 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2814 SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize;
2815 SectionSegments[i].Flags = 0;
2816 SectionSegments[i].ReferenceCount = 1;
2817 SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress;
2818 ExInitializeFastMutex(&SectionSegments[i].Lock);
2820 if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject,
2821 (LONG)ImageSectionObject, 0))
2824 * An other thread has initialized the some image in the background
2826 ExFreePool(ImageSectionObject);
2827 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2828 Section->ImageSection = ImageSectionObject;
2829 SectionSegments = ImageSectionObject->Segments;
2831 for (i = 0; i < NrSegments; i++)
2833 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2836 ExFreePool(ImageSections);
2841 * Create the section
2843 Status = ObRosCreateObject(SectionHandle,
2846 MmSectionObjectType,
2848 if (!NT_SUCCESS(Status))
2850 ObDereferenceObject(FileObject);
2857 Section->SectionPageProtection = SectionPageProtection;
2858 Section->AllocationAttributes = AllocationAttributes;
2859 InitializeListHead(&Section->ViewListHead);
2860 KeInitializeSpinLock(&Section->ViewListLock);
2863 * Check file access required
2865 if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
2867 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2871 FileAccess = FILE_READ_DATA;
2877 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2882 if (Status != STATUS_SUCCESS)
2884 ZwClose(*SectionHandle);
2885 ObDereferenceObject(Section);
2886 ObDereferenceObject(FileObject);
2890 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
2891 Section->ImageSection = ImageSectionObject;
2892 SectionSegments = ImageSectionObject->Segments;
2893 NrSegments = ImageSectionObject->NrSegments;
2896 * Otherwise just reference all the section segments
2898 for (i = 0; i < NrSegments; i++)
2900 InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount);
2904 Section->FileObject = FileObject;
2905 CcRosReferenceCache(FileObject);
2906 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2907 ObDereferenceObject(Section);
2908 return(STATUS_SUCCESS);
2915 NtCreateSection (OUT PHANDLE SectionHandle,
2916 IN ACCESS_MASK DesiredAccess,
2917 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2918 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2919 IN ULONG SectionPageProtection OPTIONAL,
2920 IN ULONG AllocationAttributes,
2921 IN HANDLE FileHandle OPTIONAL)
2923 if (AllocationAttributes & SEC_IMAGE)
2925 return(MmCreateImageSection(SectionHandle,
2929 SectionPageProtection,
2930 AllocationAttributes,
2933 else if (FileHandle != NULL)
2935 return(MmCreateDataFileSection(SectionHandle,
2939 SectionPageProtection,
2940 AllocationAttributes,
2945 return(MmCreatePageFileSection(SectionHandle,
2949 SectionPageProtection,
2950 AllocationAttributes));
2955 /**********************************************************************
2973 NtOpenSection(PHANDLE SectionHandle,
2974 ACCESS_MASK DesiredAccess,
2975 POBJECT_ATTRIBUTES ObjectAttributes)
2981 Status = ObOpenObjectByName(ObjectAttributes,
2982 MmSectionObjectType,
2993 MmMapViewOfSegment(PEPROCESS Process,
2994 PMADDRESS_SPACE AddressSpace,
2995 PSECTION_OBJECT Section,
2996 PMM_SECTION_SEGMENT Segment,
3007 Status = MmCreateMemoryArea(Process,
3009 MEMORY_AREA_SECTION_VIEW,
3016 if (!NT_SUCCESS(Status))
3018 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3019 (*BaseAddress), (*BaseAddress) + ViewSize);
3023 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3024 InsertTailList(&Section->ViewListHead,
3025 &MArea->Data.SectionData.ViewListEntry);
3026 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3028 ObReferenceObjectByPointer((PVOID)Section,
3031 ExGetPreviousMode());
3032 MArea->Data.SectionData.Segment = Segment;
3033 MArea->Data.SectionData.Section = Section;
3034 MArea->Data.SectionData.ViewOffset = ViewOffset;
3035 MArea->Data.SectionData.WriteCopyView = FALSE;
3036 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
3037 ViewSize, 0, Protect);
3039 return(STATUS_SUCCESS);
3043 /**********************************************************************
3045 * NtMapViewOfSection
3048 * Maps a view of a section into the virtual address space of a
3053 * Handle of the section.
3056 * Handle of the process.
3059 * Desired base address (or NULL) on entry;
3060 * Actual base address of the view on exit.
3063 * Number of high order address bits that must be zero.
3066 * Size in bytes of the initially committed section of
3070 * Offset in bytes from the beginning of the section
3071 * to the beginning of the view.
3074 * Desired length of map (or zero to map all) on entry
3075 * Actual length mapped on exit.
3077 * InheritDisposition
3078 * Specified how the view is to be shared with
3082 * Type of allocation for the pages.
3085 * Protection for the committed region of the view.
3093 NtMapViewOfSection(HANDLE SectionHandle,
3094 HANDLE ProcessHandle,
3098 PLARGE_INTEGER SectionOffset,
3100 SECTION_INHERIT InheritDisposition,
3101 ULONG AllocationType,
3104 PSECTION_OBJECT Section;
3107 PMADDRESS_SPACE AddressSpace;
3109 Status = ObReferenceObjectByHandle(ProcessHandle,
3110 PROCESS_VM_OPERATION,
3115 if (!NT_SUCCESS(Status))
3120 AddressSpace = &Process->AddressSpace;
3122 Status = ObReferenceObjectByHandle(SectionHandle,
3124 MmSectionObjectType,
3128 if (!(NT_SUCCESS(Status)))
3130 DPRINT("ObReference failed rc=%x\n",Status);
3131 ObDereferenceObject(Process);
3135 Status = MmMapViewOfSection(Section,
3146 ObDereferenceObject(Section);
3147 ObDereferenceObject(Process);
3153 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
3154 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry,
3159 PFILE_OBJECT FileObject;
3162 SWAPENTRY SavedSwapEntry;
3164 LARGE_INTEGER Timeout;
3166 PSECTION_OBJECT Section;
3167 PMM_SECTION_SEGMENT Segment;
3169 MArea = (PMEMORY_AREA)Context;
3171 Address = (PVOID)PAGE_ROUND_DOWN(Address);
3173 Offset = ((ULONG)Address - (ULONG)MArea->BaseAddress);
3175 Section = MArea->Data.SectionData.Section;
3176 Segment = MArea->Data.SectionData.Segment;
3179 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3183 MmUnlockSectionSegment(Segment);
3184 MmUnlockAddressSpace(&MArea->Process->AddressSpace);
3186 Timeout.QuadPart = -100000000LL; // 10 sec
3187 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
3192 if (Status != STATUS_SUCCESS)
3194 DPRINT1("Failed to wait for page op, status = %x\n", Status);
3198 MmLockAddressSpace(&MArea->Process->AddressSpace);
3199 MmLockSectionSegment(Segment);
3200 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
3201 MmReleasePageOp(PageOp);
3202 PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset);
3205 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
3208 * For a dirty, datafile, non-private page mark it as dirty in the
3211 if (Segment->Flags & MM_DATAFILE_SEGMENT)
3213 if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty)
3215 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
3216 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
3217 CcRosMarkDirtyCacheSegment(Bcb, Offset);
3218 assert(SwapEntry == 0);
3227 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3229 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3232 MmFreeSwapPage(SwapEntry);
3234 else if (PhysAddr.QuadPart != 0)
3236 if (IS_SWAP_FROM_SSE(Entry) ||
3237 PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry)))
3242 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
3244 DPRINT1("Found a private page in a pagefile section.\n");
3248 * Just dereference private pages
3250 SavedSwapEntry = MmGetSavedSwapEntryPage(PhysAddr);
3251 if (SavedSwapEntry != 0)
3253 MmFreeSwapPage(SavedSwapEntry);
3254 MmSetSavedSwapEntryPage(PhysAddr, 0);
3256 MmDeleteRmap(PhysAddr, MArea->Process, Address);
3257 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
3261 MmDeleteRmap(PhysAddr, MArea->Process, Address);
3262 MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty);
3263 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
3269 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace,
3273 PMEMORY_AREA MemoryArea;
3274 PSECTION_OBJECT Section;
3275 PMM_SECTION_SEGMENT Segment;
3277 PLIST_ENTRY CurrentEntry;
3278 PMM_REGION CurrentRegion;
3279 PLIST_ENTRY RegionListHead;
3281 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3283 if (MemoryArea == NULL)
3285 return(STATUS_UNSUCCESSFUL);
3288 MemoryArea->DeleteInProgress = TRUE;
3289 Section = MemoryArea->Data.SectionData.Section;
3290 Segment = MemoryArea->Data.SectionData.Segment;
3292 MmLockSectionSegment(Segment);
3293 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3294 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3295 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3297 RegionListHead = &MemoryArea->Data.SectionData.RegionListHead;
3298 while (!IsListEmpty(RegionListHead))
3300 CurrentEntry = RemoveHeadList(RegionListHead);
3301 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3302 ExFreePool(CurrentRegion);
3305 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
3307 Status = MmFreeMemoryArea(AddressSpace,
3315 Status = MmFreeMemoryArea(AddressSpace,
3321 MmUnlockSectionSegment(Segment);
3322 ObDereferenceObject(Section);
3323 return(STATUS_SUCCESS);
3330 MmUnmapViewOfSection(PEPROCESS Process,
3334 PMEMORY_AREA MemoryArea;
3335 PMADDRESS_SPACE AddressSpace;
3336 PSECTION_OBJECT Section;
3338 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3339 Process, BaseAddress);
3343 AddressSpace = &Process->AddressSpace;
3344 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
3346 if (MemoryArea == NULL)
3348 return(STATUS_UNSUCCESSFUL);
3351 Section = MemoryArea->Data.SectionData.Section;
3353 if (Section->AllocationAttributes & SEC_IMAGE)
3357 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3358 PMM_SECTION_SEGMENT SectionSegments;
3359 PVOID ImageBaseAddress;
3360 PMM_SECTION_SEGMENT Segment;
3362 Segment = MemoryArea->Data.SectionData.Segment;
3363 ImageSectionObject = Section->ImageSection;
3364 SectionSegments = ImageSectionObject->Segments;
3365 NrSegments = ImageSectionObject->NrSegments;
3367 /* Search for the current segment within the section segments
3368 * and calculate the image base address */
3369 for (i = 0; i < NrSegments; i++)
3371 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3373 if (Segment == &SectionSegments[i])
3375 ImageBaseAddress = BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress;
3380 if (i >= NrSegments)
3385 for (i = 0; i < NrSegments; i++)
3387 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3389 PVOID SBaseAddress = (PVOID)
3390 (ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3392 Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress);
3398 Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress);
3400 return(STATUS_SUCCESS);
3403 /**********************************************************************
3405 * NtUnmapViewOfSection
3420 NtUnmapViewOfSection (HANDLE ProcessHandle,
3426 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3427 ProcessHandle, BaseAddress);
3429 DPRINT("Referencing process\n");
3430 Status = ObReferenceObjectByHandle(ProcessHandle,
3431 PROCESS_VM_OPERATION,
3436 if (!NT_SUCCESS(Status))
3438 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3442 MmLockAddressSpace(&Process->AddressSpace);
3443 Status = MmUnmapViewOfSection(Process, BaseAddress);
3444 MmUnlockAddressSpace(&Process->AddressSpace);
3446 ObDereferenceObject(Process);
3453 NtQuerySection (IN HANDLE SectionHandle,
3454 IN CINT SectionInformationClass,
3455 OUT PVOID SectionInformation,
3457 OUT PULONG ResultLength)
3459 * FUNCTION: Queries the information of a section object.
3461 * SectionHandle = Handle to the section link object
3462 * SectionInformationClass = Index to a certain information structure
3463 * SectionInformation (OUT)= Caller supplies storage for resulting
3465 * Length = Size of the supplied storage
3466 * ResultLength = Data written
3471 PSECTION_OBJECT Section;
3474 Status = ObReferenceObjectByHandle(SectionHandle,
3476 MmSectionObjectType,
3480 if (!(NT_SUCCESS(Status)))
3485 switch (SectionInformationClass)
3487 case SectionBasicInformation:
3489 PSECTION_BASIC_INFORMATION Sbi;
3491 if (Length != sizeof(SECTION_BASIC_INFORMATION))
3493 ObDereferenceObject(Section);
3494 return(STATUS_INFO_LENGTH_MISMATCH);
3497 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3499 Sbi->BaseAddress = 0;
3500 Sbi->Attributes = 0;
3501 Sbi->Size.QuadPart = 0;
3503 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3504 Status = STATUS_SUCCESS;
3508 case SectionImageInformation:
3510 PSECTION_IMAGE_INFORMATION Sii;
3512 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3514 ObDereferenceObject(Section);
3515 return(STATUS_INFO_LENGTH_MISMATCH);
3518 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
3519 memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION));
3520 if (Section->AllocationAttributes & SEC_IMAGE)
3522 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3523 ImageSectionObject = Section->ImageSection;
3525 Sii->EntryPoint = ImageSectionObject->EntryPoint;
3526 Sii->StackReserve = ImageSectionObject->StackReserve;
3527 Sii->StackCommit = ImageSectionObject->StackCommit;
3528 Sii->Subsystem = ImageSectionObject->Subsystem;
3529 Sii->MinorSubsystemVersion = ImageSectionObject->MinorSubsystemVersion;
3530 Sii->MajorSubsystemVersion = ImageSectionObject->MajorSubsystemVersion;
3531 Sii->Characteristics = ImageSectionObject->ImageCharacteristics;
3532 Sii->ImageNumber = ImageSectionObject->Machine;
3533 Sii->Executable = ImageSectionObject->Executable;
3535 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3536 Status = STATUS_SUCCESS;
3542 Status = STATUS_INVALID_INFO_CLASS;
3544 ObDereferenceObject(Section);
3550 NtExtendSection(IN HANDLE SectionHandle,
3551 IN ULONG NewMaximumSize)
3554 return(STATUS_NOT_IMPLEMENTED);
3558 /**********************************************************************
3560 * MmAllocateSection@4
3570 * Code taken from ntoskrnl/mm/special.c.
3575 MmAllocateSection (IN ULONG Length)
3581 PMADDRESS_SPACE AddressSpace;
3583 DPRINT("MmAllocateSection(Length %x)\n",Length);
3585 AddressSpace = MmGetKernelAddressSpace();
3587 MmLockAddressSpace(AddressSpace);
3588 Status = MmCreateMemoryArea (NULL,
3597 if (!NT_SUCCESS(Status))
3599 MmUnlockAddressSpace(AddressSpace);
3602 MmUnlockAddressSpace(AddressSpace);
3603 DPRINT("Result %p\n",Result);
3604 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
3606 PHYSICAL_ADDRESS Page;
3608 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3609 if (!NT_SUCCESS(Status))
3611 DbgPrint("Unable to allocate page\n");
3614 Status = MmCreateVirtualMapping (NULL,
3615 (Result + (i * PAGE_SIZE)),
3619 if (!NT_SUCCESS(Status))
3621 DbgPrint("Unable to create virtual mapping\n");
3625 return ((PVOID)Result);
3629 /**********************************************************************
3631 * MmMapViewOfSection
3634 * Maps a view of a section into the virtual address space of a
3639 * Pointer to the section object.
3642 * Pointer to the process.
3645 * Desired base address (or NULL) on entry;
3646 * Actual base address of the view on exit.
3649 * Number of high order address bits that must be zero.
3652 * Size in bytes of the initially committed section of
3656 * Offset in bytes from the beginning of the section
3657 * to the beginning of the view.
3660 * Desired length of map (or zero to map all) on entry
3661 * Actual length mapped on exit.
3663 * InheritDisposition
3664 * Specified how the view is to be shared with
3668 * Type of allocation for the pages.
3671 * Protection for the committed region of the view.
3679 MmMapViewOfSection(IN PVOID SectionObject,
3680 IN PEPROCESS Process,
3681 IN OUT PVOID *BaseAddress,
3683 IN ULONG CommitSize,
3684 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3685 IN OUT PULONG ViewSize,
3686 IN SECTION_INHERIT InheritDisposition,
3687 IN ULONG AllocationType,
3690 PSECTION_OBJECT Section;
3691 PMADDRESS_SPACE AddressSpace;
3693 NTSTATUS Status = STATUS_SUCCESS;
3697 Section = (PSECTION_OBJECT)SectionObject;
3698 AddressSpace = &Process->AddressSpace;
3700 MmLockAddressSpace(AddressSpace);
3702 if (Section->AllocationAttributes & SEC_IMAGE)
3708 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
3709 PMM_SECTION_SEGMENT SectionSegments;
3711 ImageSectionObject = Section->ImageSection;
3712 SectionSegments = ImageSectionObject->Segments;
3713 NrSegments = ImageSectionObject->NrSegments;
3716 ImageBase = *BaseAddress;
3717 if (ImageBase == NULL)
3719 ImageBase = ImageSectionObject->ImageBase;
3723 for (i = 0; i < NrSegments; i++)
3725 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3728 MaxExtent = (ULONG)(SectionSegments[i].VirtualAddress +
3729 SectionSegments[i].Length);
3730 ImageSize = max(ImageSize, MaxExtent);
3734 /* Check there is enough space to map the section at that point. */
3735 if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
3736 PAGE_ROUND_UP(ImageSize)) != NULL)
3738 /* Fail if the user requested a fixed base address. */
3739 if ((*BaseAddress) != NULL)
3741 MmUnlockAddressSpace(AddressSpace);
3742 return(STATUS_UNSUCCESSFUL);
3744 /* Otherwise find a gap to map the image. */
3745 ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), FALSE);
3746 if (ImageBase == NULL)
3748 MmUnlockAddressSpace(AddressSpace);
3749 return(STATUS_UNSUCCESSFUL);
3753 for (i = 0; i < NrSegments; i++)
3757 if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3759 SBaseAddress = (PVOID)
3760 (ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress);
3761 MmLockSectionSegment(&SectionSegments[i]);
3762 Status = MmMapViewOfSegment(Process,
3765 &SectionSegments[i],
3767 SectionSegments[i].Length,
3768 SectionSegments[i].Protection,
3769 (ULONG_PTR)SectionSegments[i].VirtualAddress,
3771 MmUnlockSectionSegment(&SectionSegments[i]);
3772 if (!NT_SUCCESS(Status))
3774 MmUnlockAddressSpace(AddressSpace);
3780 *BaseAddress = ImageBase;
3784 if (SectionOffset == NULL)
3790 ViewOffset = SectionOffset->u.LowPart;
3793 if ((ViewOffset % PAGE_SIZE) != 0)
3795 MmUnlockAddressSpace(AddressSpace);
3796 return(STATUS_MAPPED_ALIGNMENT);
3799 if ((*ViewSize) == 0)
3801 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3803 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3805 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3808 MmLockSectionSegment(Section->Segment);
3809 Status = MmMapViewOfSegment(Process,
3817 (AllocationType & MEM_TOP_DOWN));
3818 MmUnlockSectionSegment(Section->Segment);
3819 if (!NT_SUCCESS(Status))
3821 MmUnlockAddressSpace(AddressSpace);
3826 MmUnlockAddressSpace(AddressSpace);
3828 return(STATUS_SUCCESS);
3835 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3836 IN PLARGE_INTEGER NewFileSize)
3847 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3857 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3858 IN MMFLUSH_TYPE FlushType)
3862 case MmFlushForDelete:
3863 if (SectionObjectPointer->ImageSectionObject ||
3864 SectionObjectPointer->DataSectionObject)
3868 CcRosSetRemoveOnClose(SectionObjectPointer);
3870 case MmFlushForWrite:
3880 MmForceSectionClosed (DWORD Unknown0,
3892 MmMapViewInSystemSpace (IN PVOID SectionObject,
3893 OUT PVOID * MappedBase,
3894 IN OUT PULONG ViewSize)
3896 PSECTION_OBJECT Section;
3897 PMADDRESS_SPACE AddressSpace;
3900 DPRINT("MmMapViewInSystemSpace() called\n");
3902 Section = (PSECTION_OBJECT)SectionObject;
3903 AddressSpace = MmGetKernelAddressSpace();
3905 MmLockAddressSpace(AddressSpace);
3908 if ((*ViewSize) == 0)
3910 (*ViewSize) = Section->MaximumSize.u.LowPart;
3912 else if ((*ViewSize) > Section->MaximumSize.u.LowPart)
3914 (*ViewSize) = Section->MaximumSize.u.LowPart;
3917 MmLockSectionSegment(Section->Segment);
3920 Status = MmMapViewOfSegment(NULL,
3930 MmUnlockSectionSegment(Section->Segment);
3931 MmUnlockAddressSpace(AddressSpace);
3941 MmUnmapViewInSystemSpace (IN PVOID MappedBase)
3943 PMADDRESS_SPACE AddressSpace;
3946 DPRINT("MmUnmapViewInSystemSpace() called\n");
3948 AddressSpace = MmGetKernelAddressSpace();
3950 Status = MmUnmapViewOfSegment(AddressSpace, MappedBase);
3960 MmSetBankedSection (DWORD Unknown0,
3968 return (STATUS_NOT_IMPLEMENTED);
3972 /**********************************************************************
3977 * Creates a section object.
3980 * SectionObjiect (OUT)
3981 * Caller supplied storage for the resulting pointer
3982 * to a SECTION_OBJECT instance;
3985 * Specifies the desired access to the section can be a
3987 * STANDARD_RIGHTS_REQUIRED |
3989 * SECTION_MAP_WRITE |
3990 * SECTION_MAP_READ |
3991 * SECTION_MAP_EXECUTE
3993 * ObjectAttributes [OPTIONAL]
3994 * Initialized attributes for the object can be used
3995 * to create a named section;
3998 * Maximizes the size of the memory section. Must be
3999 * non-NULL for a page-file backed section.
4000 * If value specified for a mapped file and the file is
4001 * not large enough, file will be extended.
4003 * SectionPageProtection
4004 * Can be a combination of:
4010 * AllocationAttributes
4011 * Can be a combination of:
4016 * Handle to a file to create a section mapped to a file
4017 * instead of a memory backed section;
4028 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
4029 IN ACCESS_MASK DesiredAccess,
4030 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
4031 IN PLARGE_INTEGER MaximumSize,
4032 IN ULONG SectionPageProtection,
4033 IN ULONG AllocationAttributes,
4034 IN HANDLE FileHandle OPTIONAL,
4035 IN PFILE_OBJECT File OPTIONAL)
4037 return (STATUS_NOT_IMPLEMENTED);