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 #include <ddk/ntddk.h>
33 #include <internal/mm.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37 #include <internal/cc.h>
38 #include <ddk/ntifs.h>
39 #include <ntos/minmax.h>
42 #include <internal/debug.h>
44 /* TYPES *********************************************************************/
48 PSECTION_OBJECT Section;
49 PMM_SECTION_SEGMENT Segment;
53 } MM_SECTION_PAGEOUT_CONTEXT;
55 /* GLOBALS *******************************************************************/
57 POBJECT_TYPE EXPORTED MmSectionObjectType = NULL;
59 static GENERIC_MAPPING MmpSectionMapping = {
60 STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY,
61 STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE,
62 STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
65 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
66 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
68 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
69 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
70 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
71 #define MAX_SHARE_COUNT 0x7FF
72 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
73 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
74 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
76 /* FUNCTIONS *****************************************************************/
79 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment)
83 for (i = 0; i < NR_SECTION_PAGE_TABLES; i++)
85 if (Segment->PageDirectory.PageTables[i] != NULL)
87 ExFreePool(Segment->PageDirectory.PageTables[i]);
93 MmFreeSectionSegments(PFILE_OBJECT FileObject)
95 if (FileObject->SectionObjectPointers->ImageSectionObject != NULL)
97 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
102 (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointers->
105 for (i = 0; i < ImageSectionObject->NrSegments; i++)
107 if (ImageSectionObject->Segments[i].ReferenceCount != 0)
109 DPRINT1("Image segment %d still referenced (was %d)\n", i,
110 ImageSectionObject->Segments[i].ReferenceCount);
113 MmFreePageTablesSectionSegment(&ImageSectionObject->Segments[i]);
115 ExFreePool(ImageSectionObject);
116 FileObject->SectionObjectPointers->ImageSectionObject = NULL;
118 if (FileObject->SectionObjectPointers->DataSectionObject != NULL)
120 PMM_SECTION_SEGMENT Segment;
122 Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers->
125 if (Segment->ReferenceCount != 0)
127 DPRINT1("Data segment still referenced\n");
130 MmFreePageTablesSectionSegment(Segment);
132 FileObject->SectionObjectPointers->DataSectionObject = NULL;
137 MmLockSection(PSECTION_OBJECT Section)
139 KeWaitForSingleObject(&Section->Lock,
147 MmUnlockSection(PSECTION_OBJECT Section)
149 KeReleaseMutex(&Section->Lock, FALSE);
153 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment)
155 KeWaitForSingleObject(&Segment->Lock,
163 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment)
165 KeReleaseMutex(&Segment->Lock, FALSE);
169 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
173 PSECTION_PAGE_TABLE Table;
174 ULONG DirectoryOffset;
177 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
178 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
182 Segment->PageDirectory.PageTables[DirectoryOffset] =
183 ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE),
184 TAG_SECTION_PAGE_TABLE);
185 memset(Table, 0, sizeof(SECTION_PAGE_TABLE));
186 DPRINT("Table %x\n", Table);
188 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
189 Table->Entry[TableOffset] = Entry;
194 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
197 PSECTION_PAGE_TABLE Table;
199 ULONG DirectoryOffset;
202 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset);
204 DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset);
205 Table = Segment->PageDirectory.PageTables[DirectoryOffset];
206 DPRINT("Table %x\n", Table);
211 TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset);
212 Entry = Table->Entry[TableOffset];
217 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
222 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
225 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
228 if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT)
230 DPRINT1("Maximum share count reached\n");
233 if (IS_SWAP_FROM_SSE(Entry))
237 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1);
238 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
242 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section,
243 PMM_SECTION_SEGMENT Segment,
249 Entry = MmGetPageEntrySectionSegment(Segment, Offset);
252 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
255 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
257 DPRINT1("Zero share count for unshare\n");
260 if (IS_SWAP_FROM_SSE(Entry))
264 Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1);
266 * If we reducing the share count of this entry to zero then set the entry
267 * to zero and tell the cache the page is no longer mapped.
269 if (SHARE_COUNT_FROM_SSE(Entry) == 0)
271 PFILE_OBJECT FileObject;
272 PREACTOS_COMMON_FCB_HEADER Fcb;
273 SWAPENTRY SavedSwapEntry;
274 PHYSICAL_ADDRESS Page;
276 MmSetPageEntrySectionSegment(Segment, Offset, 0);
277 FileObject = Section->FileObject;
278 if (FileObject != NULL)
280 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
282 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
283 (Offset % PAGE_SIZE) == 0)
286 Status = CcRosUnmapCacheSegment(Fcb->Bcb, Offset, Dirty);
287 if (!NT_SUCCESS(Status))
294 Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry);
295 SavedSwapEntry = MmGetSavedSwapEntryPage(Page);
296 if (SavedSwapEntry != 0)
298 MmFreeSwapPage(SavedSwapEntry);
299 MmSetSavedSwapEntryPage(Page, 0);
304 MmSetPageEntrySectionSegment(Segment, Offset, Entry);
306 return(SHARE_COUNT_FROM_SSE(Entry) > 1);
310 MiReadPage(PMEMORY_AREA MemoryArea,
311 PLARGE_INTEGER Offset,
312 PHYSICAL_ADDRESS* Page)
314 * FUNCTION: Read a page for a section backed memory area.
316 * MemoryArea - Memory area to read the page for.
317 * Offset - Offset of the page to read.
318 * Page - Variable that receives a page contains the read data.
321 IO_STATUS_BLOCK IoStatus;
322 PFILE_OBJECT FileObject;
325 PREACTOS_COMMON_FCB_HEADER Fcb;
328 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
329 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
332 * If the file system is letting us go directly to the cache and the
333 * memory area was mapped at an offset in the file which is page aligned
334 * then get the related cache segment.
336 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
337 (Offset->QuadPart % PAGE_SIZE) == 0)
342 PCACHE_SEGMENT CacheSeg;
343 PHYSICAL_ADDRESS Addr;
346 * Get the related cache segment; we use a lower level interface than
347 * filesystems do because it is safe for us to use an offset with a
348 * alignment less than the file system block size.
350 Status = CcRosGetCacheSegment(Fcb->Bcb,
351 (ULONG)Offset->QuadPart,
356 if (!NT_SUCCESS(Status))
363 * If the cache segment isn't up to date then call the file
364 * system to read in the data.
366 Status = ReadCacheSegment(CacheSeg);
367 if (!NT_SUCCESS(Status))
373 * Retrieve the page from the cache segment that we actually want.
375 Addr = MmGetPhysicalAddress(BaseAddress +
376 Offset->QuadPart - BaseOffset);
378 MmReferencePage((*Page));
380 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, TRUE, FALSE, TRUE);
381 return(STATUS_SUCCESS);
386 * Allocate a page, this is rather complicated by the possibility
387 * we might have to move other things out of memory
389 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
390 if (!NT_SUCCESS(Status))
396 * Create an mdl to hold the page we are going to read data into.
398 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
399 MmBuildMdlFromPages(Mdl, &Page->u.LowPart);
401 * Call the FSD to read the page
404 KeInitializeEvent(&Event, NotificationEvent, FALSE);
405 Status = IoPageRead(FileObject,
410 if (Status == STATUS_PENDING)
412 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
413 return(IoStatus.Status);
420 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
421 MEMORY_AREA* MemoryArea,
425 LARGE_INTEGER Offset;
429 PSECTION_OBJECT Section;
430 PMM_SECTION_SEGMENT Segment;
438 * There is a window between taking the page fault and locking the
439 * address space when another thread could load the page so we check
442 if (MmIsPagePresent(NULL, Address))
446 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
448 return(STATUS_SUCCESS);
451 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
452 Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) +
453 MemoryArea->Data.SectionData.ViewOffset;
458 Segment = MemoryArea->Data.SectionData.Segment;
459 Section = MemoryArea->Data.SectionData.Section;
460 Region = MmFindRegion(MemoryArea->BaseAddress,
461 &MemoryArea->Data.SectionData.RegionListHead,
463 MmLockSection(Section);
464 MmLockSectionSegment(Segment);
467 * Check if this page needs to be mapped COW
469 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
470 (Region->Protect == PAGE_READWRITE ||
471 Region->Protect == PAGE_EXECUTE_READWRITE))
473 Attributes = PAGE_READONLY;
477 Attributes = Region->Protect;
481 * Get or create a page operation descriptor
483 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart,
487 DPRINT1("MmGetPageOp failed\n");
492 * Check if someone else is already handling this fault, if so wait
495 if (PageOp->Thread != PsGetCurrentThread())
497 MmUnlockSectionSegment(Segment);
498 MmUnlockSection(Section);
499 MmUnlockAddressSpace(AddressSpace);
500 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
506 * Check for various strange conditions
508 if (Status != STATUS_SUCCESS)
510 DPRINT1("Failed to wait for page op\n");
513 if (PageOp->Status == STATUS_PENDING)
515 DPRINT1("Woke for page op before completion\n");
519 * If this wasn't a pagein then restart the operation
521 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
523 MmLockAddressSpace(AddressSpace);
524 MmReleasePageOp(PageOp);
525 DPRINT("Address 0x%.8X\n", Address);
526 return(STATUS_MM_RESTART_OPERATION);
529 * If the thread handling this fault has failed then we don't retry
531 if (!NT_SUCCESS(PageOp->Status))
533 MmLockAddressSpace(AddressSpace);
534 DPRINT("Address 0x%.8X\n", Address);
535 return(PageOp->Status);
537 MmLockAddressSpace(AddressSpace);
538 MmLockSection(Section);
539 MmLockSectionSegment(Segment);
541 * If the completed fault was for another address space then set the
544 if (!MmIsPagePresent(NULL, Address))
546 Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart);
549 MmUnlockSectionSegment(Segment);
550 MmUnlockSection(Section);
551 MmReleasePageOp(PageOp);
552 return(STATUS_MM_RESTART_OPERATION);
555 Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry));
556 MmReferencePage(Page);
557 MmSharePageEntrySectionSegment(Segment, Offset.u.LowPart);
559 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
564 if (!NT_SUCCESS(Status))
566 DbgPrint("Unable to create virtual mapping\n");
569 MmInsertRmap(Page, PsGetCurrentProcess(),
570 (PVOID)PAGE_ROUND_DOWN(Address));
574 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
576 MmUnlockSectionSegment(Segment);
577 MmUnlockSection(Section);
578 MmReleasePageOp(PageOp);
579 DPRINT("Address 0x%.8X\n", Address);
580 return(STATUS_SUCCESS);
584 * Must be private page we have swapped out.
586 if (MmIsPageSwapEntry(NULL, (PVOID)PAddress))
591 MmUnlockSectionSegment(Segment);
592 MmUnlockSection(Section);
594 MmDeletePageFileMapping(NULL, (PVOID)PAddress, &SwapEntry);
596 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
597 if (!NT_SUCCESS(Status))
602 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
603 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
604 Status = MmReadFromSwapPage(SwapEntry, Mdl);
605 if (!NT_SUCCESS(Status))
610 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
615 while (Status == STATUS_NO_MEMORY)
617 MmUnlockAddressSpace(AddressSpace);
618 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
623 MmLockAddressSpace(AddressSpace);
625 if (!NT_SUCCESS(Status))
627 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
633 * Store the swap entry for later use.
635 MmSetSavedSwapEntryPage(Page, SwapEntry);
638 * Add the page to the process's working set
640 MmInsertRmap(Page, PsGetCurrentProcess(),
641 (PVOID)PAGE_ROUND_DOWN(Address));
644 * Finish the operation
648 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
650 PageOp->Status = STATUS_SUCCESS;
651 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
652 MmReleasePageOp(PageOp);
653 DPRINT("Address 0x%.8X\n", Address);
654 return(STATUS_SUCCESS);
658 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
660 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
663 * Just map the desired physical page
665 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
671 * Don't add an rmap entry since the page mapped could be for
676 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
680 * Cleanup and release locks
682 PageOp->Status = STATUS_SUCCESS;
683 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
684 MmReleasePageOp(PageOp);
685 MmUnlockSectionSegment(Segment);
686 MmUnlockSection(Section);
687 DPRINT("Address 0x%.8X\n", Address);
688 return(STATUS_SUCCESS);
692 * Map anonymous memory for BSS sections
694 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
696 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
697 if (!NT_SUCCESS(Status))
699 MmUnlockSectionSegment(Segment);
700 MmUnlockSection(Section);
701 MmUnlockAddressSpace(AddressSpace);
702 MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
703 MmLockAddressSpace(AddressSpace);
704 MmLockSection(Section);
705 MmLockSectionSegment(Segment);
708 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
713 MmInsertRmap(Page, PsGetCurrentProcess(),
714 (PVOID)PAGE_ROUND_DOWN(Address));
717 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
721 * Cleanup and release locks
723 PageOp->Status = STATUS_SUCCESS;
724 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
725 MmReleasePageOp(PageOp);
726 MmUnlockSectionSegment(Segment);
727 MmUnlockSection(Section);
728 DPRINT("Address 0x%.8X\n", Address);
729 return(STATUS_SUCCESS);
733 * Get the entry corresponding to the offset within the section
735 Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart);
740 * If the entry is zero (and it can't change because we have
741 * locked the segment) then we need to load the page.
745 * Release all our locks and read in the page from disk
747 MmUnlockSectionSegment(Segment);
748 MmUnlockSection(Section);
749 MmUnlockAddressSpace(AddressSpace);
751 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
753 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
757 Status = MiReadPage(MemoryArea, &Offset, &Page);
759 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
762 * FIXME: What do we know in this case?
764 DPRINT1("IoPageRead failed (Status %x)\n", Status);
767 * Cleanup and release locks
769 PageOp->Status = Status;
770 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
771 MmReleasePageOp(PageOp);
772 MmLockAddressSpace(AddressSpace);
777 * Relock the address space, section and segment
779 MmLockAddressSpace(AddressSpace);
780 MmLockSection(Section);
781 MmLockSectionSegment(Segment);
784 * Check the entry. No one should change the status of a page
785 * that has a pending page-in.
787 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
790 DbgPrint("Someone changed ppte entry while we slept\n");
795 * Mark the offset within the section as having valid, in-memory
798 Entry = Page.u.LowPart;
799 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
800 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
802 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
807 if (!NT_SUCCESS(Status))
809 MmUnlockSectionSegment(Segment);
810 MmUnlockSection(Section);
811 MmUnlockAddressSpace(AddressSpace);
812 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
817 if (!NT_SUCCESS(Status))
821 MmLockAddressSpace(AddressSpace);
822 MmLockSection(Section);
823 MmLockSectionSegment(Segment);
825 MmInsertRmap(Page, PsGetCurrentProcess(),
826 (PVOID)PAGE_ROUND_DOWN(Address));
827 if (!NT_SUCCESS(Status))
829 DbgPrint("Unable to create virtual mapping\n");
834 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
836 PageOp->Status = STATUS_SUCCESS;
837 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
838 MmReleasePageOp(PageOp);
839 MmUnlockSectionSegment(Segment);
840 MmUnlockSection(Section);
841 DPRINT("MmNotPresentFaultSectionView succeeded\n");
842 return(STATUS_SUCCESS);
844 else if (IS_SWAP_FROM_SSE(Entry))
849 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
852 * Release all our locks and read in the page from disk
854 MmUnlockSectionSegment(Segment);
855 MmUnlockSection(Section);
856 MmUnlockAddressSpace(AddressSpace);
858 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
859 if (!NT_SUCCESS(Status))
864 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
865 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
866 Status = MmReadFromSwapPage(SwapEntry, Mdl);
867 if (!NT_SUCCESS(Status))
873 * Relock the address space, section and segment
875 MmLockAddressSpace(AddressSpace);
876 MmLockSection(Section);
877 MmLockSectionSegment(Segment);
880 * Check the entry. No one should change the status of a page
881 * that has a pending page-in.
883 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
886 DbgPrint("Someone changed ppte entry while we slept\n");
891 * Mark the offset within the section as having valid, in-memory
894 Entry = Page.u.LowPart;
895 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
896 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
899 * Save the swap entry.
901 MmSetSavedSwapEntryPage(Page, SwapEntry);
903 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
908 MmInsertRmap(Page, PsGetCurrentProcess(),
909 (PVOID)PAGE_ROUND_DOWN(Address));
910 if (!NT_SUCCESS(Status))
912 DbgPrint("Unable to create virtual mapping\n");
917 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
919 PageOp->Status = STATUS_SUCCESS;
920 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
921 MmReleasePageOp(PageOp);
922 MmUnlockSectionSegment(Segment);
923 MmUnlockSection(Section);
924 DPRINT("MmNotPresentFaultSectionView succeeded\n");
925 return(STATUS_SUCCESS);
930 * If the section offset is already in-memory and valid then just
931 * take another reference to the page
934 Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry);
935 MmReferencePage(Page);
936 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
938 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
943 MmInsertRmap(Page, PsGetCurrentProcess(),
944 (PVOID)PAGE_ROUND_DOWN(Address));
945 if (!NT_SUCCESS(Status))
947 DbgPrint("Unable to create virtual mapping\n");
952 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
954 PageOp->Status = STATUS_SUCCESS;
955 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
956 MmReleasePageOp(PageOp);
957 MmUnlockSectionSegment(Segment);
958 MmUnlockSection(Section);
959 return(STATUS_SUCCESS);
964 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
965 MEMORY_AREA* MemoryArea,
969 PMM_SECTION_SEGMENT Segment;
970 PSECTION_OBJECT Section;
971 PHYSICAL_ADDRESS OldPage;
972 PHYSICAL_ADDRESS NewPage;
976 LARGE_INTEGER Offset;
981 * Check if the page has been paged out or has already been set readwrite
983 if (!MmIsPagePresent(NULL, Address) ||
984 MmGetPageProtect(NULL, Address) & PAGE_READWRITE)
986 return(STATUS_SUCCESS);
990 * Find the offset of the page
992 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
993 Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) +
994 MemoryArea->Data.SectionData.ViewOffset;
999 Segment = MemoryArea->Data.SectionData.Segment;
1000 Section = MemoryArea->Data.SectionData.Section;
1001 Region = MmFindRegion(MemoryArea->BaseAddress,
1002 &MemoryArea->Data.SectionData.RegionListHead,
1004 MmLockSection(Section);
1005 MmLockSectionSegment(Segment);
1010 if (MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) == 0)
1012 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1017 * Check if we are doing COW
1019 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1020 (Region->Protect == PAGE_READWRITE ||
1021 Region->Protect == PAGE_EXECUTE_READWRITE)))
1023 MmUnlockSection(Section);
1024 MmUnlockSectionSegment(Segment);
1025 return(STATUS_UNSUCCESSFUL);
1029 * Get or create a pageop
1031 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart,
1032 MM_PAGEOP_ACCESSFAULT);
1035 DPRINT1("MmGetPageOp failed\n");
1040 * Wait for any other operations to complete
1042 if (PageOp->Thread != PsGetCurrentThread())
1044 MmUnlockSectionSegment(Segment);
1045 MmUnlockSection(Section);
1046 MmUnlockAddressSpace(AddressSpace);
1047 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
1053 * Check for various strange conditions
1055 if (Status != STATUS_SUCCESS)
1057 DPRINT1("Failed to wait for page op\n");
1060 if (PageOp->Status == STATUS_PENDING)
1062 DPRINT1("Woke for page op before completion\n");
1066 * Restart the operation
1068 MmLockAddressSpace(AddressSpace);
1069 MmReleasePageOp(PageOp);
1070 return(STATUS_MM_RESTART_OPERATION);
1074 * Release locks now we have the pageop
1076 MmUnlockSectionSegment(Segment);
1077 MmUnlockSection(Section);
1078 MmUnlockAddressSpace(AddressSpace);
1083 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1088 OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
1090 NewAddress = ExAllocatePageWithPhysPage(NewPage);
1091 memcpy(NewAddress, (PVOID)PAGE_ROUND_DOWN(Address), PAGE_SIZE);
1092 ExUnmapPage(NewAddress);
1095 * Delete the old entry.
1097 MmDeleteVirtualMapping(PsGetCurrentProcess(), Address, FALSE, NULL, NULL);
1100 * Set the PTE to point to the new page
1102 MmLockAddressSpace(AddressSpace);
1103 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
1108 MmInsertRmap(NewPage, PsGetCurrentProcess(),
1109 (PVOID)PAGE_ROUND_DOWN(Address));
1110 if (!NT_SUCCESS(Status))
1112 DbgPrint("Unable to create virtual mapping\n");
1117 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
1121 * Unshare the old page.
1123 MmUnsharePageEntrySectionSegment(Section, Segment, Offset.QuadPart, FALSE);
1124 MmDeleteRmap(OldPage, PsGetCurrentProcess(),
1125 (PVOID)PAGE_ROUND_DOWN(Address));
1126 MmReleasePageMemoryConsumer(MC_USER, OldPage);
1128 PageOp->Status = STATUS_SUCCESS;
1129 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1130 MmReleasePageOp(PageOp);
1131 return(STATUS_SUCCESS);
1135 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1137 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1139 PHYSICAL_ADDRESS PhysicalAddress;
1141 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1142 MmDeleteVirtualMapping(Process,
1149 PageOutContext->WasDirty = TRUE;
1151 if (!PageOutContext->Private)
1153 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1154 PageOutContext->Segment,
1155 PageOutContext->Offset.u.LowPart,
1156 PageOutContext->WasDirty);
1158 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1162 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1163 MEMORY_AREA* MemoryArea,
1167 LARGE_INTEGER Offset;
1168 PSECTION_OBJECT Section;
1169 PMM_SECTION_SEGMENT Segment;
1170 PHYSICAL_ADDRESS PhysicalAddress;
1171 MM_SECTION_PAGEOUT_CONTEXT Context;
1172 SWAPENTRY SwapEntry;
1177 PFILE_OBJECT FileObject;
1178 PREACTOS_COMMON_FCB_HEADER Fcb;
1179 BOOLEAN DirectMapped;
1181 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1183 Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1184 MemoryArea->Data.SectionData.ViewOffset;
1186 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1187 DirectMapped = FALSE;
1188 if (FileObject != NULL)
1190 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
1193 * If the file system is letting us go directly to the cache and the
1194 * memory area was mapped at an offset in the file which is page aligned
1195 * then note this is a direct mapped page.
1197 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1198 (Offset.QuadPart % PAGE_SIZE) == 0)
1200 DirectMapped = TRUE;
1205 * Get the segment and section.
1207 Segment = MemoryArea->Data.SectionData.Segment;
1208 Section = MemoryArea->Data.SectionData.Section;
1211 * This should never happen since mappings of physical memory are never
1212 * placed in the rmap lists.
1214 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1216 DPRINT1("Trying to page out from physical memory section address 0x%X "
1217 "process %d\n", Address, AddressSpace->Process->UniqueProcessId);
1222 * Get the section segment entry and the physical address.
1224 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1225 if (!MmIsPagePresent(AddressSpace->Process, Address))
1227 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1228 AddressSpace->Process->UniqueProcessId, Address);
1232 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1233 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1236 * Prepare the context structure for the rmap delete call.
1238 Context.Section = Section;
1239 Context.Segment = Segment;
1240 Context.Offset = Offset;
1241 Context.WasDirty = FALSE;
1242 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1243 IS_SWAP_FROM_SSE(Entry) ||
1244 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1246 Context.Private = Private = TRUE;
1250 Context.Private = Private = FALSE;
1254 * Take an additional reference to the page.
1256 MmReferencePage(PhysicalAddress);
1259 * Paging out data mapped read-only is easy.
1261 if (MemoryArea->Attributes & PAGE_READONLY ||
1262 MemoryArea->Attributes & PAGE_EXECUTE_READ)
1265 * Read-only data should never be in the swapfile.
1269 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1270 "paddress 0x%.8X\n", SwapEntry, Address,
1276 * Read-only data should never be COWed
1280 DPRINT1("Had private copy of read-only page.\n");
1285 * Delete all mappings of this page.
1287 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context,
1288 MmPageOutDeleteMapping);
1289 if (Context.WasDirty)
1294 * If this page wasn't direct mapped then we have a private copy so
1295 * release back to the system; otherwise the cache manager will have
1296 * handled freeing the cache segment which we mapped from.
1300 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1303 PageOp->Status = STATUS_SUCCESS;
1304 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1305 MmReleasePageOp(PageOp);
1306 return(STATUS_SUCCESS);
1310 * Otherwise we have read-write data.
1312 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
1315 * If this wasn't a private page then we should have reduced the entry to
1316 * zero by deleting all the rmaps.
1318 if (!Private && MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) != 0)
1324 * If the page wasn't dirty then we can just free it as for a readonly page.
1325 * Since we unmapped all the mappings above we know it will not suddenly
1328 if (!Context.WasDirty)
1330 if (!DirectMapped || Private)
1332 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1333 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1337 if (!(Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
1340 DPRINT1("Private page, non-dirty but not swapped out "
1341 "process %d address 0x%.8X\n",
1342 AddressSpace->Process->UniqueProcessId,
1348 Status = MmCreatePageFileMapping(AddressSpace->Process,
1351 if (!NT_SUCCESS(Status))
1358 PageOp->Status = STATUS_SUCCESS;
1359 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1360 MmReleasePageOp(PageOp);
1361 return(STATUS_SUCCESS);
1365 * If this page was direct mapped from the cache then the cache manager
1366 * will already have taken care of writing it back.
1368 if (DirectMapped && !Private)
1370 assert(SwapEntry == 0);
1371 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1372 PageOp->Status = STATUS_SUCCESS;
1373 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1374 MmReleasePageOp(PageOp);
1375 return(STATUS_SUCCESS);
1379 * If necessary, allocate an entry in the paging file for this page
1381 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1384 SwapEntry = MmAllocSwapPage();
1387 MmShowOutOfSpaceMessagePagingFile();
1390 * For private pages restore the old mappings.
1394 Status = MmCreateVirtualMapping(MemoryArea->Process,
1396 MemoryArea->Attributes,
1399 MmSetDirtyPage(MemoryArea->Process, Address);
1400 MmInsertRmap(PhysicalAddress,
1401 MemoryArea->Process,
1407 * For non-private pages if the page wasn't direct mapped then
1408 * set it back into the section segment entry so we don't loose
1409 * our copy. Otherwise it will be handled by the cache manager.
1411 Status = MmCreateVirtualMapping(MemoryArea->Process,
1413 MemoryArea->Attributes,
1416 MmSetDirtyPage(MemoryArea->Process, Address);
1417 MmInsertRmap(PhysicalAddress,
1418 MemoryArea->Process,
1420 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart,
1421 PhysicalAddress.u.LowPart);
1422 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
1424 PageOp->Status = STATUS_UNSUCCESSFUL;
1425 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1426 MmReleasePageOp(PageOp);
1427 return(STATUS_UNSUCCESSFUL);
1432 * Write the page to the pagefile
1434 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1435 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1436 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1437 if (!NT_SUCCESS(Status))
1439 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1442 * As above: undo our actions.
1443 * FIXME: Also free the swap page.
1447 Status = MmCreateVirtualMapping(MemoryArea->Process,
1449 MemoryArea->Attributes,
1452 MmSetDirtyPage(MemoryArea->Process, Address);
1453 MmInsertRmap(PhysicalAddress,
1454 MemoryArea->Process,
1459 Status = MmCreateVirtualMapping(MemoryArea->Process,
1461 MemoryArea->Attributes,
1464 MmSetDirtyPage(MemoryArea->Process, Address);
1465 MmInsertRmap(PhysicalAddress,
1466 MemoryArea->Process,
1468 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart,
1469 PhysicalAddress.u.LowPart);
1470 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
1472 PageOp->Status = STATUS_UNSUCCESSFUL;
1473 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1474 MmReleasePageOp(PageOp);
1475 return(STATUS_UNSUCCESSFUL);
1479 * Otherwise we have succeeded.
1481 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1482 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1483 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1487 Status = MmCreatePageFileMapping(MemoryArea->Process,
1490 if (!NT_SUCCESS(Status))
1497 Entry = MAKE_SWAP_SSE(SwapEntry);
1498 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
1501 PageOp->Status = STATUS_SUCCESS;
1502 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1503 MmReleasePageOp(PageOp);
1504 return(STATUS_SUCCESS);
1508 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1509 PMEMORY_AREA MemoryArea,
1513 LARGE_INTEGER Offset;
1514 PSECTION_OBJECT Section;
1515 PMM_SECTION_SEGMENT Segment;
1516 PHYSICAL_ADDRESS PhysicalAddress;
1517 SWAPENTRY SwapEntry;
1522 PFILE_OBJECT FileObject;
1523 PREACTOS_COMMON_FCB_HEADER Fcb = NULL;
1524 BOOLEAN DirectMapped;
1526 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1528 Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1529 MemoryArea->Data.SectionData.ViewOffset;
1531 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1532 DirectMapped = FALSE;
1533 if (FileObject != NULL)
1535 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
1538 * If the file system is letting us go directly to the cache and the
1539 * memory area was mapped at an offset in the file which is page aligned
1540 * then note this is a direct mapped page.
1542 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1543 (Offset.QuadPart % PAGE_SIZE) == 0)
1545 DirectMapped = TRUE;
1550 * Get the segment and section.
1552 Segment = MemoryArea->Data.SectionData.Segment;
1553 Section = MemoryArea->Data.SectionData.Section;
1556 * This should never happen since mappings of physical memory are never
1557 * placed in the rmap lists.
1559 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1561 DPRINT1("Trying to write back page from physical memory mapped at %X "
1562 "process %d\n", Address, AddressSpace->Process->UniqueProcessId);
1567 * Get the section segment entry and the physical address.
1569 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1570 if (!MmIsPagePresent(AddressSpace->Process, Address))
1572 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1573 AddressSpace->Process->UniqueProcessId, Address);
1577 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1578 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1581 * Check for a private (COWed) page.
1583 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1584 IS_SWAP_FROM_SSE(Entry) ||
1585 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1595 * Speculatively set all mappings of the page to clean.
1597 MmSetCleanAllRmaps(PhysicalAddress);
1600 * If this page was direct mapped from the cache then the cache manager
1601 * will take care of writing it back to disk.
1603 if (DirectMapped && !Private)
1605 assert(SwapEntry == 0);
1606 CcRosMarkDirtyCacheSegment(Fcb->Bcb, Offset.u.LowPart);
1607 PageOp->Status = STATUS_SUCCESS;
1608 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1609 MmReleasePageOp(PageOp);
1610 return(STATUS_SUCCESS);
1614 * If necessary, allocate an entry in the paging file for this page
1616 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1619 SwapEntry = MmAllocSwapPage();
1622 MmSetDirtyAllRmaps(PhysicalAddress);
1623 PageOp->Status = STATUS_UNSUCCESSFUL;
1624 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1625 MmReleasePageOp(PageOp);
1626 return(STATUS_UNSUCCESSFUL);
1631 * Write the page to the pagefile
1633 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1634 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1635 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1636 if (!NT_SUCCESS(Status))
1638 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1640 MmSetDirtyAllRmaps(PhysicalAddress);
1641 PageOp->Status = STATUS_UNSUCCESSFUL;
1642 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1643 MmReleasePageOp(PageOp);
1644 return(STATUS_UNSUCCESSFUL);
1648 * Otherwise we have succeeded.
1650 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1651 MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
1652 PageOp->Status = STATUS_SUCCESS;
1653 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1654 MmReleasePageOp(PageOp);
1655 return(STATUS_SUCCESS);
1659 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1667 PMEMORY_AREA MemoryArea;
1668 PMM_SECTION_SEGMENT Segment;
1672 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1673 Segment = MemoryArea->Data.SectionData.Segment;
1675 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1676 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1681 if (OldProtect != NewProtect)
1683 for (i = 0; i < (RegionSize / PAGE_SIZE); i++)
1685 PVOID Address = BaseAddress + (i * PAGE_SIZE);
1686 ULONG Protect = NewProtect;
1689 * If we doing COW for this segment then check if the page is
1692 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1694 LARGE_INTEGER Offset;
1696 LARGE_INTEGER PhysicalAddress;
1699 (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1700 MemoryArea->Data.SectionData.ViewOffset;
1701 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1703 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1705 Protect = PAGE_READONLY;
1706 if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1707 IS_SWAP_FROM_SSE(Entry) ||
1708 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart))
1710 Protect = NewProtect;
1714 if (MmIsPagePresent(AddressSpace->Process, Address))
1716 MmSetPageProtect(AddressSpace->Process, BaseAddress,
1724 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1725 PMEMORY_AREA MemoryArea,
1735 min(Length, MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress);
1736 Region = MmFindRegion(MemoryArea->BaseAddress,
1737 &MemoryArea->Data.SectionData.RegionListHead,
1739 *OldProtect = Region->Protect;
1740 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1741 &MemoryArea->Data.SectionData.RegionListHead,
1742 BaseAddress, Length, Region->Type, Protect,
1743 MmAlterViewAttributes);
1749 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1751 PMEMORY_BASIC_INFORMATION Info,
1752 PULONG ResultLength)
1755 PVOID RegionBaseAddress;
1757 Region = MmFindRegion(MemoryArea->BaseAddress,
1758 &MemoryArea->Data.SectionData.RegionListHead,
1759 Address, &RegionBaseAddress);
1760 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
1761 Info->AllocationBase = MemoryArea->BaseAddress;
1762 Info->AllocationProtect = MemoryArea->Attributes;
1763 Info->RegionSize = MemoryArea->Length;
1764 Info->State = MEM_COMMIT;
1765 Info->Protect = Region->Protect;
1766 if (MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE)
1768 Info->Type = MEM_IMAGE;
1772 Info->Type = MEM_MAPPED;
1775 return(STATUS_SUCCESS);
1779 MmpDeleteSection(PVOID ObjectBody)
1781 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
1783 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
1784 if (Section->AllocationAttributes & SEC_IMAGE)
1788 for (i = 0; i < Section->NrSegments; i++)
1790 InterlockedDecrement(&Section->Segments[i].ReferenceCount);
1795 InterlockedDecrement(&Section->Segments->ReferenceCount);
1797 if (Section->FileObject != NULL)
1799 CcRosDereferenceCache(Section->FileObject);
1800 ObDereferenceObject(Section->FileObject);
1801 Section->FileObject = NULL;
1806 MmpCloseSection(PVOID ObjectBody,
1809 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
1810 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
1815 MmpCreateSection(PVOID ObjectBody,
1817 PWSTR RemainingPath,
1818 POBJECT_ATTRIBUTES ObjectAttributes)
1820 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
1821 ObjectBody, Parent, RemainingPath);
1823 if (RemainingPath == NULL)
1825 return(STATUS_SUCCESS);
1828 if (wcschr(RemainingPath+1, L'\\') != NULL)
1830 return(STATUS_UNSUCCESSFUL);
1833 return(STATUS_SUCCESS);
1837 MmCreatePhysicalMemorySection(VOID)
1839 HANDLE PhysSectionH;
1840 PSECTION_OBJECT PhysSection;
1842 OBJECT_ATTRIBUTES Obj;
1843 UNICODE_STRING Name = UNICODE_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
1844 LARGE_INTEGER SectionSize;
1847 * Create the section mapping physical memory
1849 SectionSize.QuadPart = 0xFFFFFFFF;
1850 InitializeObjectAttributes(&Obj,
1855 Status = NtCreateSection(&PhysSectionH,
1859 PAGE_EXECUTE_READWRITE,
1862 if (!NT_SUCCESS(Status))
1864 DbgPrint("Failed to create PhysicalMemory section\n");
1867 Status = ObReferenceObjectByHandle(PhysSectionH,
1871 (PVOID*)&PhysSection,
1873 if (!NT_SUCCESS(Status))
1875 DbgPrint("Failed to reference PhysicalMemory section\n");
1878 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
1879 ObDereferenceObject((PVOID)PhysSection);
1881 return(STATUS_SUCCESS);
1885 MmInitSectionImplementation(VOID)
1887 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
1889 RtlInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
1891 MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
1892 MmSectionObjectType->TotalObjects = 0;
1893 MmSectionObjectType->TotalHandles = 0;
1894 MmSectionObjectType->MaxObjects = ULONG_MAX;
1895 MmSectionObjectType->MaxHandles = ULONG_MAX;
1896 MmSectionObjectType->PagedPoolCharge = 0;
1897 MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
1898 MmSectionObjectType->Mapping = &MmpSectionMapping;
1899 MmSectionObjectType->Dump = NULL;
1900 MmSectionObjectType->Open = NULL;
1901 MmSectionObjectType->Close = MmpCloseSection;
1902 MmSectionObjectType->Delete = MmpDeleteSection;
1903 MmSectionObjectType->Parse = NULL;
1904 MmSectionObjectType->Security = NULL;
1905 MmSectionObjectType->QueryName = NULL;
1906 MmSectionObjectType->OkayToClose = NULL;
1907 MmSectionObjectType->Create = MmpCreateSection;
1908 MmSectionObjectType->DuplicationNotify = NULL;
1910 return(STATUS_SUCCESS);
1914 MmCreatePageFileSection(PHANDLE SectionHandle,
1915 ACCESS_MASK DesiredAccess,
1916 POBJECT_ATTRIBUTES ObjectAttributes,
1917 PLARGE_INTEGER UMaximumSize,
1918 ULONG SectionPageProtection,
1919 ULONG AllocationAttributes)
1921 * Create a section which is backed by the pagefile
1924 LARGE_INTEGER MaximumSize;
1925 PSECTION_OBJECT Section;
1926 PMM_SECTION_SEGMENT Segment;
1929 if (UMaximumSize == NULL)
1931 return(STATUS_UNSUCCESSFUL);
1933 MaximumSize = *UMaximumSize;
1936 * Check the protection
1938 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
1939 SectionPageProtection)
1941 return(STATUS_INVALID_PAGE_PROTECTION);
1945 * Create the section
1947 Status = ObCreateObject(SectionHandle,
1950 MmSectionObjectType,
1952 if (!NT_SUCCESS(Status))
1960 Section->SectionPageProtection = SectionPageProtection;
1961 Section->AllocationAttributes = AllocationAttributes;
1962 InitializeListHead(&Section->ViewListHead);
1963 KeInitializeSpinLock(&Section->ViewListLock);
1964 KeInitializeMutex(&Section->Lock, 0);
1965 Section->FileObject = NULL;
1966 Section->MaximumSize = MaximumSize;
1967 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
1968 TAG_MM_SECTION_SEGMENT);
1969 if (Segment == NULL)
1971 ZwClose(*SectionHandle);
1972 ObDereferenceObject(Section);
1973 return(STATUS_NO_MEMORY);
1975 Section->Segments = Segment;
1976 Segment->ReferenceCount = 1;
1977 KeInitializeMutex(&Segment->Lock, 0);
1978 Segment->FileOffset = 0;
1979 Segment->Protection = SectionPageProtection;
1980 Segment->Attributes = AllocationAttributes;
1981 Segment->Length = MaximumSize.u.LowPart;
1982 Segment->Flags = MM_PAGEFILE_SEGMENT;
1983 Segment->WriteCopy = FALSE;
1984 return(STATUS_SUCCESS);
1989 MmCreateDataFileSection(PHANDLE SectionHandle,
1990 ACCESS_MASK DesiredAccess,
1991 POBJECT_ATTRIBUTES ObjectAttributes,
1992 PLARGE_INTEGER UMaximumSize,
1993 ULONG SectionPageProtection,
1994 ULONG AllocationAttributes,
1997 * Create a section backed by a data file
2000 PSECTION_OBJECT Section;
2002 LARGE_INTEGER MaximumSize;
2003 PFILE_OBJECT FileObject;
2004 PMM_SECTION_SEGMENT Segment;
2008 * Check the protection
2010 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2011 SectionPageProtection)
2013 return(STATUS_INVALID_PAGE_PROTECTION);
2017 * Create the section
2019 Status = ObCreateObject(SectionHandle,
2022 MmSectionObjectType,
2024 if (!NT_SUCCESS(Status))
2032 Section->SectionPageProtection = SectionPageProtection;
2033 Section->AllocationAttributes = AllocationAttributes;
2034 InitializeListHead(&Section->ViewListHead);
2035 KeInitializeSpinLock(&Section->ViewListLock);
2036 KeInitializeMutex(&Section->Lock, 0);
2037 Section->NrSegments = 1;
2038 Section->ImageBase = NULL;
2039 Section->EntryPoint = NULL;
2040 Section->StackReserve = 0;
2041 Section->StackCommit = 0;
2042 Section->Subsystem = 0;
2043 Section->MinorSubsystemVersion = 0;
2044 Section->MajorSubsystemVersion = 0;
2045 Section->ImageCharacteristics = 0;
2046 Section->Machine = 0;
2047 Section->Executable = FALSE;
2050 * Check file access required
2052 if (SectionPageProtection & PAGE_READWRITE ||
2053 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2055 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2059 FileAccess = FILE_READ_DATA;
2063 * Reference the file handle
2065 Status = ObReferenceObjectByHandle(FileHandle,
2069 (PVOID*)&FileObject,
2071 if (!NT_SUCCESS(Status))
2073 ZwClose(*SectionHandle);
2074 ObDereferenceObject(Section);
2079 * We can't do memory mappings if the file system doesn't support the
2082 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2084 ZwClose(*SectionHandle);
2085 ObDereferenceObject(Section);
2086 ObDereferenceObject(FileObject);
2087 return(STATUS_INVALID_FILE_FOR_SECTION);
2091 * FIXME: Revise this once a locking order for file size changes is
2094 if (UMaximumSize != NULL)
2096 MaximumSize = *UMaximumSize;
2101 ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
2104 if (MaximumSize.QuadPart >
2105 ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
2107 IO_STATUS_BLOCK Iosb;
2108 Status = NtSetInformationFile(FileHandle,
2111 sizeof(LARGE_INTEGER),
2112 FileAllocationInformation);
2113 if (!NT_SUCCESS(Status))
2115 ZwClose(*SectionHandle);
2116 ObDereferenceObject(Section);
2117 ObDereferenceObject(FileObject);
2118 return(STATUS_SECTION_NOT_EXTENDED);
2125 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2130 if (Status != STATUS_SUCCESS)
2132 ZwClose(*SectionHandle);
2133 ObDereferenceObject(Section);
2134 ObDereferenceObject(FileObject);
2139 * If this file hasn't been mapped as a data file before then allocate a
2140 * section segment to describe the data file mapping
2142 if (FileObject->SectionObjectPointers->DataSectionObject == NULL)
2144 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2145 TAG_MM_SECTION_SEGMENT);
2146 if (Segment == NULL)
2148 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2149 ZwClose(*SectionHandle);
2150 ObDereferenceObject(Section);
2151 ObDereferenceObject(FileObject);
2152 return(STATUS_NO_MEMORY);
2154 Section->Segments = Segment;
2155 Segment->ReferenceCount = 1;
2156 KeInitializeMutex(&Segment->Lock, 0);
2159 * Set the lock before assigning the segment to the file object
2161 Status = KeWaitForSingleObject((PVOID)&Segment->Lock,
2166 if (Status != STATUS_SUCCESS)
2168 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2169 ExFreePool(Segment);
2170 ZwClose(*SectionHandle);
2171 ObDereferenceObject(Section);
2172 ObDereferenceObject(FileObject);
2175 FileObject->SectionObjectPointers->DataSectionObject = (PVOID)Segment;
2177 Segment->FileOffset = 0;
2178 Segment->Protection = 0;
2179 Segment->Attributes = 0;
2180 Segment->Flags = MM_DATAFILE_SEGMENT;
2181 Segment->Characteristics = 0;
2182 Segment->WriteCopy = FALSE;
2183 if (AllocationAttributes & SEC_RESERVE)
2185 Segment->Length = 0;
2189 Segment->Length = MaximumSize.u.LowPart;
2191 Segment->VirtualAddress = NULL;
2196 * If the file is already mapped as a data file then we may need
2200 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers->
2202 Section->Segments = Segment;
2203 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2204 Status = KeWaitForSingleObject((PVOID)&Segment->Lock,
2209 if (Status != STATUS_SUCCESS)
2211 InterlockedDecrement((PLONG)&Segment->ReferenceCount);
2212 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2213 ZwClose(*SectionHandle);
2214 ObDereferenceObject(Section);
2215 ObDereferenceObject(FileObject);
2218 if (MaximumSize.u.LowPart > Segment->Length &&
2219 !(AllocationAttributes & SEC_RESERVE))
2221 Segment->Length = MaximumSize.u.LowPart;
2224 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2225 CcRosReferenceCache(FileObject);
2226 Section->FileObject = FileObject;
2227 Section->MaximumSize = MaximumSize;
2228 KeReleaseMutex(&Segment->Lock, FALSE);
2230 ObDereferenceObject(Section);
2231 return(STATUS_SUCCESS);
2234 static ULONG SectionCharacteristicsToProtect[16] =
2236 PAGE_NOACCESS, // 0 = NONE
2237 PAGE_NOACCESS, // 1 = SHARED
2238 PAGE_EXECUTE, // 2 = EXECUTABLE
2239 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
2240 PAGE_READONLY, // 4 = READABLE
2241 PAGE_READONLY, // 5 = READABLE, SHARED
2242 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
2243 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
2244 PAGE_READWRITE, // 8 = WRITABLE
2245 PAGE_READWRITE, // 9 = WRITABLE, SHARED
2246 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
2247 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
2248 PAGE_READWRITE, // 12 = WRITABLE, READABLE
2249 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
2250 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
2251 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2255 MmCreateImageSection(PHANDLE SectionHandle,
2256 ACCESS_MASK DesiredAccess,
2257 POBJECT_ATTRIBUTES ObjectAttributes,
2258 PLARGE_INTEGER UMaximumSize,
2259 ULONG SectionPageProtection,
2260 ULONG AllocationAttributes,
2263 PSECTION_OBJECT Section;
2265 PFILE_OBJECT FileObject;
2267 IMAGE_DOS_HEADER DosHeader;
2268 IO_STATUS_BLOCK Iosb;
2269 LARGE_INTEGER Offset;
2270 IMAGE_NT_HEADERS PEHeader;
2271 PIMAGE_SECTION_HEADER ImageSections;
2272 PMM_SECTION_SEGMENT SectionSegments;
2274 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2277 * Check the protection
2279 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2280 SectionPageProtection)
2282 return(STATUS_INVALID_PAGE_PROTECTION);
2286 * Specifying a maximum size is meaningless for an image section
2288 if (UMaximumSize != NULL)
2290 return(STATUS_INVALID_PARAMETER_4);
2294 * Read the dos header
2296 Offset.QuadPart = 0;
2297 Status = ZwReadFile(FileHandle,
2306 if (!NT_SUCCESS(Status))
2310 if (Iosb.Information != sizeof(DosHeader))
2312 return(STATUS_INVALID_IMAGE_FORMAT);
2316 * Check the DOS signature
2318 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2320 return(STATUS_INVALID_IMAGE_FORMAT);
2324 * Read the PE header
2326 Offset.QuadPart = DosHeader.e_lfanew;
2327 Status = ZwReadFile(FileHandle,
2336 if (!NT_SUCCESS(Status))
2340 if (Iosb.Information != sizeof(PEHeader))
2342 return(STATUS_INVALID_IMAGE_FORMAT);
2346 * Check the signature
2348 if (PEHeader.Signature != IMAGE_NT_SIGNATURE)
2350 return(STATUS_INVALID_IMAGE_FORMAT);
2354 * Read in the section headers
2356 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2358 ExAllocatePool(NonPagedPool,
2359 PEHeader.FileHeader.NumberOfSections *
2360 sizeof(IMAGE_SECTION_HEADER));
2361 Status = ZwReadFile(FileHandle,
2367 PEHeader.FileHeader.NumberOfSections *
2368 sizeof(IMAGE_SECTION_HEADER),
2371 if (!NT_SUCCESS(Status))
2373 ExFreePool(ImageSections);
2376 if (Iosb.Information !=
2377 (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2379 ExFreePool(ImageSections);
2380 return(STATUS_INVALID_IMAGE_FORMAT);
2384 * Create the section
2386 Status = ObCreateObject(SectionHandle,
2389 MmSectionObjectType,
2391 if (!NT_SUCCESS(Status))
2393 ExFreePool(ImageSections);
2400 Section->SectionPageProtection = SectionPageProtection;
2401 Section->AllocationAttributes = AllocationAttributes;
2402 InitializeListHead(&Section->ViewListHead);
2403 KeInitializeSpinLock(&Section->ViewListLock);
2404 KeInitializeMutex(&Section->Lock, 0);
2405 Section->NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2406 Section->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2407 Section->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2408 Section->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2409 Section->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2410 Section->Subsystem = PEHeader.OptionalHeader.Subsystem;
2411 Section->MinorSubsystemVersion =
2412 PEHeader.OptionalHeader.MinorSubsystemVersion;
2413 Section->MajorSubsystemVersion =
2414 PEHeader.OptionalHeader.MajorSubsystemVersion;
2415 Section->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2416 Section->Machine = PEHeader.FileHeader.Machine;
2417 Section->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2420 * Check file access required
2422 if (SectionPageProtection & PAGE_READWRITE ||
2423 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2425 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2429 FileAccess = FILE_READ_DATA;
2433 * Reference the file handle
2435 Status = ObReferenceObjectByHandle(FileHandle,
2439 (PVOID*)&FileObject,
2441 if (!NT_SUCCESS(Status))
2443 ZwClose(*SectionHandle);
2444 ObDereferenceObject(Section);
2445 ExFreePool(ImageSections);
2450 * We can't do memory mappings if the file system doesn't support the
2453 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2455 ZwClose(*SectionHandle);
2456 ObDereferenceObject(Section);
2457 ObDereferenceObject(FileObject);
2458 ExFreePool(ImageSections);
2459 return(STATUS_INVALID_FILE_FOR_SECTION);
2465 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2470 if (Status != STATUS_SUCCESS)
2472 ZwClose(*SectionHandle);
2473 ObDereferenceObject(Section);
2474 ObDereferenceObject(FileObject);
2475 ExFreePool(ImageSections);
2480 * If this file hasn't been mapped as a image file before then allocate the
2481 * section segments to describe the mapping
2483 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2484 if (FileObject->SectionObjectPointers->ImageSectionObject == NULL)
2488 ULONG Characteristics;
2490 Size = sizeof(MM_IMAGE_SECTION_OBJECT) +
2491 (sizeof(MM_SECTION_SEGMENT) * NrSegments);
2492 ImageSectionObject =
2493 ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2494 if (ImageSectionObject == NULL)
2496 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2497 ZwClose(*SectionHandle);
2498 ObDereferenceObject(Section);
2499 ObDereferenceObject(FileObject);
2500 ExFreePool(ImageSections);
2501 return(STATUS_NO_MEMORY);
2503 ImageSectionObject->NrSegments = NrSegments;
2504 SectionSegments = ImageSectionObject->Segments;
2505 Section->Segments = SectionSegments;
2507 SectionSegments[0].FileOffset = 0;
2508 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2509 SectionSegments[0].Protection = PAGE_READWRITE;
2510 SectionSegments[0].RawLength = PAGE_SIZE;
2511 SectionSegments[0].Length = PAGE_SIZE;
2512 SectionSegments[0].Flags = 0;
2513 SectionSegments[0].ReferenceCount = 1;
2514 SectionSegments[0].VirtualAddress = 0;
2515 SectionSegments[0].WriteCopy = TRUE;
2516 KeInitializeMutex(&SectionSegments[0].Lock, 0);
2518 for (i = 1; i < NrSegments; i++)
2520 SectionSegments[i].FileOffset =
2521 ImageSections[i-1].PointerToRawData;
2522 SectionSegments[i].Characteristics =
2523 ImageSections[i-1].Characteristics;
2526 * Set up the protection and write copy variables.
2528 Characteristics = ImageSections[i - 1].Characteristics;
2529 if ((Characteristics & IMAGE_SECTION_CHAR_READABLE) ||
2530 (Characteristics & IMAGE_SECTION_CHAR_WRITABLE) ||
2531 (Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE))
2533 SectionSegments[i].Protection =
2534 SectionCharacteristicsToProtect[Characteristics >> 28];
2535 SectionSegments[i].WriteCopy =
2536 !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2538 else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2540 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2541 SectionSegments[i].WriteCopy = TRUE;
2543 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2545 SectionSegments[i].Protection = PAGE_READWRITE;
2546 SectionSegments[i].WriteCopy = TRUE;
2548 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2550 SectionSegments[i].Protection = PAGE_READWRITE;
2551 SectionSegments[i].WriteCopy = TRUE;
2555 SectionSegments[i].Protection = PAGE_NOACCESS;
2556 SectionSegments[i].WriteCopy = TRUE;
2560 * Set up the attributes.
2562 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2564 SectionSegments[i].Attributes = 0;
2566 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2568 SectionSegments[i].Attributes = 0;
2570 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2572 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2576 SectionSegments[i].Attributes = 0;
2579 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2580 SectionSegments[i].Length =
2581 ImageSections[i-1].Misc.VirtualSize;
2582 SectionSegments[i].Flags = 0;
2583 SectionSegments[i].ReferenceCount = 1;
2584 SectionSegments[i].VirtualAddress =
2585 (PVOID)ImageSections[i-1].VirtualAddress;
2586 KeInitializeMutex(&SectionSegments[i].Lock, 0);
2589 FileObject->SectionObjectPointers->ImageSectionObject =
2590 (PVOID)ImageSectionObject;
2596 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)
2597 FileObject->SectionObjectPointers->ImageSectionObject;
2598 SectionSegments = ImageSectionObject->Segments;
2599 Section->Segments = SectionSegments;
2602 * Otherwise just reference all the section segments
2604 for (i = 0; i < NrSegments; i++)
2606 InterlockedIncrement(&SectionSegments[i].ReferenceCount);
2610 ExFreePool(ImageSections);
2611 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2612 CcRosReferenceCache(FileObject);
2613 Section->FileObject = FileObject;
2615 ObDereferenceObject(Section);
2616 return(STATUS_SUCCESS);
2620 NtCreateSection (OUT PHANDLE SectionHandle,
2621 IN ACCESS_MASK DesiredAccess,
2622 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2623 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2624 IN ULONG SectionPageProtection OPTIONAL,
2625 IN ULONG AllocationAttributes,
2626 IN HANDLE FileHandle OPTIONAL)
2628 if (AllocationAttributes & SEC_IMAGE)
2630 return(MmCreateImageSection(SectionHandle,
2634 SectionPageProtection,
2635 AllocationAttributes,
2638 else if (FileHandle != NULL)
2640 return(MmCreateDataFileSection(SectionHandle,
2644 SectionPageProtection,
2645 AllocationAttributes,
2650 return(MmCreatePageFileSection(SectionHandle,
2654 SectionPageProtection,
2655 AllocationAttributes));
2660 /**********************************************************************
2679 NtOpenSection(PHANDLE SectionHandle,
2680 ACCESS_MASK DesiredAccess,
2681 POBJECT_ATTRIBUTES ObjectAttributes)
2687 Status = ObOpenObjectByName(ObjectAttributes,
2688 MmSectionObjectType,
2699 MmMapViewOfSegment(PEPROCESS Process,
2700 PMADDRESS_SPACE AddressSpace,
2701 PSECTION_OBJECT Section,
2702 PMM_SECTION_SEGMENT Segment,
2712 Status = MmCreateMemoryArea(Process,
2713 &Process->AddressSpace,
2714 MEMORY_AREA_SECTION_VIEW,
2720 if (!NT_SUCCESS(Status))
2722 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
2723 (*BaseAddress), (*BaseAddress) + ViewSize);
2727 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
2728 InsertTailList(&Section->ViewListHead,
2729 &MArea->Data.SectionData.ViewListEntry);
2730 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
2732 ObReferenceObjectByPointer((PVOID)Section,
2735 ExGetPreviousMode());
2736 MArea->Data.SectionData.Segment = Segment;
2737 MArea->Data.SectionData.Section = Section;
2738 MArea->Data.SectionData.ViewOffset = ViewOffset;
2739 MArea->Data.SectionData.WriteCopyView = FALSE;
2740 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
2741 ViewSize, 0, Protect);
2743 return(STATUS_SUCCESS);
2747 /**********************************************************************
2749 * NtMapViewOfSection
2752 * Maps a view of a section into the virtual address space of a
2757 * Handle of the section.
2760 * Handle of the process.
2763 * Desired base address (or NULL) on entry;
2764 * Actual base address of the view on exit.
2767 * Number of high order address bits that must be zero.
2770 * Size in bytes of the initially committed section of
2774 * Offset in bytes from the beginning of the section
2775 * to the beginning of the view.
2778 * Desired length of map (or zero to map all) on entry
2779 * Actual length mapped on exit.
2781 * InheritDisposition
2782 * Specified how the view is to be shared with
2786 * Type of allocation for the pages.
2789 * Protection for the committed region of the view.
2795 NtMapViewOfSection(HANDLE SectionHandle,
2796 HANDLE ProcessHandle,
2800 PLARGE_INTEGER SectionOffset,
2802 SECTION_INHERIT InheritDisposition,
2803 ULONG AllocationType,
2806 PSECTION_OBJECT Section;
2809 PMADDRESS_SPACE AddressSpace;
2811 Status = ObReferenceObjectByHandle(ProcessHandle,
2812 PROCESS_VM_OPERATION,
2817 if (!NT_SUCCESS(Status))
2822 AddressSpace = &Process->AddressSpace;
2824 Status = ObReferenceObjectByHandle(SectionHandle,
2826 MmSectionObjectType,
2830 if (!(NT_SUCCESS(Status)))
2832 DPRINT("ObReference failed rc=%x\n",Status);
2833 ObDereferenceObject(Process);
2837 Status = MmMapViewOfSection(Section,
2848 ObDereferenceObject(Section);
2849 ObDereferenceObject(Process);
2855 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
2856 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry,
2861 PFILE_OBJECT FileObject;
2862 PREACTOS_COMMON_FCB_HEADER Fcb;
2864 SWAPENTRY SavedSwapEntry;
2867 MArea = (PMEMORY_AREA)Context;
2869 Offset = ((ULONG)PAGE_ROUND_DOWN(Address) - (ULONG)MArea->BaseAddress) +
2870 MArea->Data.SectionData.ViewOffset;
2871 Entry = MmGetPageEntrySectionSegment(MArea->Data.SectionData.Segment,
2874 PageOp = MmCheckForPageOp(MArea, 0, NULL, MArea->Data.SectionData.Segment,
2876 assert(PageOp == NULL);
2879 * For a dirty, datafile, non-private page mark it as dirty in the
2882 if (MArea->Data.SectionData.Segment->Flags & MM_DATAFILE_SEGMENT)
2884 if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty)
2886 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
2887 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
2888 CcRosMarkDirtyCacheSegment(Fcb->Bcb, Offset);
2889 assert(SwapEntry == 0);
2895 MmFreeSwapPage(SwapEntry);
2897 else if (PhysAddr.QuadPart != 0)
2899 if (IS_SWAP_FROM_SSE(Entry) ||
2900 PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry)))
2903 * Just dereference private pages
2905 SavedSwapEntry = MmGetSavedSwapEntryPage(PhysAddr);
2906 if (SavedSwapEntry != 0)
2908 MmFreeSwapPage(SavedSwapEntry);
2909 MmSetSavedSwapEntryPage(PhysAddr, 0);
2911 MmDeleteRmap(PhysAddr, MArea->Process, Address);
2912 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
2916 MmUnsharePageEntrySectionSegment(MArea->Data.SectionData.Section,
2917 MArea->Data.SectionData.Segment,
2920 MmDeleteRmap(PhysAddr, MArea->Process, Address);
2921 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
2927 MmUnmapViewOfSection(PEPROCESS Process,
2931 PMEMORY_AREA MemoryArea;
2932 PMADDRESS_SPACE AddressSpace;
2933 PSECTION_OBJECT Section;
2934 PMM_SECTION_SEGMENT Segment;
2936 PLIST_ENTRY CurrentEntry;
2937 PMM_REGION CurrentRegion;
2939 AddressSpace = &Process->AddressSpace;
2941 DPRINT("Opening memory area Process %x BaseAddress %x\n",
2942 Process, BaseAddress);
2943 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
2945 if (MemoryArea == NULL)
2947 return(STATUS_UNSUCCESSFUL);
2950 MemoryArea->DeleteInProgress = TRUE;
2952 MmLockSection(MemoryArea->Data.SectionData.Section);
2953 MmLockSectionSegment(MemoryArea->Data.SectionData.Segment);
2954 Section = MemoryArea->Data.SectionData.Section;
2955 Segment = MemoryArea->Data.SectionData.Segment;
2956 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
2957 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
2958 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
2960 CurrentEntry = MemoryArea->Data.SectionData.RegionListHead.Flink;
2961 while (CurrentEntry != &MemoryArea->Data.SectionData.RegionListHead)
2964 CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
2965 CurrentEntry = CurrentEntry->Flink;
2966 ExFreePool(CurrentRegion);
2969 if (MemoryArea->Data.SectionData.Section->AllocationAttributes &
2972 Status = MmFreeMemoryArea(&Process->AddressSpace,
2980 Status = MmFreeMemoryArea(&Process->AddressSpace,
2986 MmUnlockSection(Section);
2987 MmUnlockSectionSegment(Segment);
2988 ObDereferenceObject(Section);
2989 return(STATUS_SUCCESS);
2992 /**********************************************************************
2994 * NtUnmapViewOfSection
3010 NtUnmapViewOfSection (HANDLE ProcessHandle,
3016 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3017 ProcessHandle, BaseAddress);
3019 DPRINT("Referencing process\n");
3020 Status = ObReferenceObjectByHandle(ProcessHandle,
3021 PROCESS_VM_OPERATION,
3026 if (!NT_SUCCESS(Status))
3028 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3032 MmLockAddressSpace(&Process->AddressSpace);
3033 Status = MmUnmapViewOfSection(Process, BaseAddress);
3034 MmUnlockAddressSpace(&Process->AddressSpace);
3036 ObDereferenceObject(Process);
3043 NtQuerySection (IN HANDLE SectionHandle,
3044 IN CINT SectionInformationClass,
3045 OUT PVOID SectionInformation,
3047 OUT PULONG ResultLength)
3049 * FUNCTION: Queries the information of a section object.
3051 * SectionHandle = Handle to the section link object
3052 * SectionInformationClass = Index to a certain information structure
3053 * SectionInformation (OUT)= Caller supplies storage for resulting
3055 * Length = Size of the supplied storage
3056 * ResultLength = Data written
3061 PSECTION_OBJECT Section;
3064 Status = ObReferenceObjectByHandle(SectionHandle,
3066 MmSectionObjectType,
3070 if (!(NT_SUCCESS(Status)))
3075 switch (SectionInformationClass)
3077 case SectionBasicInformation:
3079 PSECTION_BASIC_INFORMATION Sbi;
3081 if (Length != sizeof(SECTION_BASIC_INFORMATION))
3083 ObDereferenceObject(Section);
3084 return(STATUS_INFO_LENGTH_MISMATCH);
3087 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3089 Sbi->BaseAddress = 0;
3090 Sbi->Attributes = 0;
3091 Sbi->Size.QuadPart = 0;
3093 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3094 Status = STATUS_SUCCESS;
3098 case SectionImageInformation:
3100 PSECTION_IMAGE_INFORMATION Sii;
3102 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3104 ObDereferenceObject(Section);
3105 return(STATUS_INFO_LENGTH_MISMATCH);
3107 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
3108 Sii->EntryPoint = Section->EntryPoint;
3110 Sii->StackReserve = Section->StackReserve;
3111 Sii->StackCommit = Section->StackCommit;
3112 Sii->Subsystem = Section->Subsystem;
3113 Sii->MinorSubsystemVersion = Section->MinorSubsystemVersion;
3114 Sii->MajorSubsystemVersion = Section->MajorSubsystemVersion;
3116 Sii->Characteristics = Section->ImageCharacteristics;
3117 Sii->ImageNumber = Section->Machine;
3118 Sii->Executable = Section->Executable;
3120 Sii->Unknown4[0] = 0;
3121 Sii->Unknown4[1] = 0;
3122 Sii->Unknown4[2] = 0;
3124 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3125 Status = STATUS_SUCCESS;
3131 Status = STATUS_INVALID_INFO_CLASS;
3133 ObDereferenceObject(Section);
3139 NtExtendSection(IN HANDLE SectionHandle,
3140 IN ULONG NewMaximumSize)
3146 /**********************************************************************
3148 * MmAllocateSection@4
3158 * Code taken from ntoskrnl/mm/special.c.
3164 MmAllocateSection (IN ULONG Length)
3170 PMADDRESS_SPACE AddressSpace;
3172 DPRINT("MmAllocateSection(Length %x)\n",Length);
3174 AddressSpace = MmGetKernelAddressSpace();
3176 MmLockAddressSpace(AddressSpace);
3177 Status = MmCreateMemoryArea (NULL,
3185 if (!NT_SUCCESS(Status))
3187 MmUnlockAddressSpace(AddressSpace);
3190 MmUnlockAddressSpace(AddressSpace);
3191 DPRINT("Result %p\n",Result);
3192 for (i = 0; (i <= (Length / PAGE_SIZE)); i++)
3194 PHYSICAL_ADDRESS Page;
3196 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3197 if (!NT_SUCCESS(Status))
3199 DbgPrint("Unable to allocate page\n");
3202 Status = MmCreateVirtualMapping (NULL,
3203 (Result + (i * PAGE_SIZE)),
3207 if (!NT_SUCCESS(Status))
3209 DbgPrint("Unable to create virtual mapping\n");
3213 return ((PVOID)Result);
3217 /**********************************************************************
3219 * MmMapViewOfSection
3222 * Maps a view of a section into the virtual address space of a
3227 * Pointer to the section object.
3230 * Pointer to the process.
3233 * Desired base address (or NULL) on entry;
3234 * Actual base address of the view on exit.
3237 * Number of high order address bits that must be zero.
3240 * Size in bytes of the initially committed section of
3244 * Offset in bytes from the beginning of the section
3245 * to the beginning of the view.
3248 * Desired length of map (or zero to map all) on entry
3249 * Actual length mapped on exit.
3251 * InheritDisposition
3252 * Specified how the view is to be shared with
3256 * Type of allocation for the pages.
3259 * Protection for the committed region of the view.
3265 MmMapViewOfSection(IN PVOID SectionObject,
3266 IN PEPROCESS Process,
3267 IN OUT PVOID *BaseAddress,
3269 IN ULONG CommitSize,
3270 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3271 IN OUT PULONG ViewSize,
3272 IN SECTION_INHERIT InheritDisposition,
3273 IN ULONG AllocationType,
3276 PSECTION_OBJECT Section;
3277 PMADDRESS_SPACE AddressSpace;
3279 NTSTATUS Status = STATUS_SUCCESS;
3281 Section = (PSECTION_OBJECT)SectionObject;
3282 AddressSpace = &Process->AddressSpace;
3284 MmLockAddressSpace(AddressSpace);
3285 MmLockSection(SectionObject);
3287 if (Section->AllocationAttributes & SEC_IMAGE)
3293 ImageBase = *BaseAddress;
3294 if (ImageBase == NULL)
3296 ImageBase = Section->ImageBase;
3300 for (i = 0; i < Section->NrSegments; i++)
3302 if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3305 MaxExtent = (ULONG)(Section->Segments[i].VirtualAddress +
3306 Section->Segments[i].Length);
3307 ImageSize = max(ImageSize, MaxExtent);
3311 /* Check there is enough space to map the section at that point. */
3312 if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
3315 /* Fail if the user requested a fixed base address. */
3316 if ((*BaseAddress) != NULL)
3318 MmUnlockSection(Section);
3319 MmUnlockAddressSpace(AddressSpace);
3322 /* Otherwise find a gap to map the image. */
3323 ImageBase = MmFindGap(AddressSpace, ImageSize);
3324 if (ImageBase == NULL)
3326 MmUnlockSection(Section);
3327 MmUnlockAddressSpace(AddressSpace);
3332 for (i = 0; i < Section->NrSegments; i++)
3336 if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3338 SBaseAddress = (PVOID)
3339 (ImageBase + (ULONG_PTR)Section->Segments[i].VirtualAddress);
3341 MmLockSectionSegment(&Section->Segments[i]);
3342 Status = MmMapViewOfSegment(Process,
3343 &Process->AddressSpace,
3345 &Section->Segments[i],
3347 Section->Segments[i].Length,
3348 Section->Segments[i].Protection,
3349 Section->Segments[i].FileOffset);
3350 MmUnlockSectionSegment(&Section->Segments[i]);
3351 if (!NT_SUCCESS(Status))
3353 MmUnlockSection(Section);
3354 MmUnlockAddressSpace(AddressSpace);
3359 *BaseAddress = ImageBase;
3363 if (SectionOffset == NULL)
3369 ViewOffset = SectionOffset->u.LowPart;
3372 if ((ViewOffset % PAGE_SIZE) != 0)
3374 MmUnlockSection(Section);
3375 MmUnlockAddressSpace(AddressSpace);
3376 return(STATUS_MAPPED_ALIGNMENT);
3379 if ((*ViewSize) == 0)
3381 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3383 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3385 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3388 MmLockSectionSegment(Section->Segments);
3389 Status = MmMapViewOfSegment(Process,
3390 &Process->AddressSpace,
3397 MmUnlockSectionSegment(Section->Segments);
3398 if (!NT_SUCCESS(Status))
3400 MmUnlockSection(Section);
3401 MmUnlockAddressSpace(AddressSpace);
3406 MmUnlockSection(Section);
3407 MmUnlockAddressSpace(AddressSpace);
3409 return(STATUS_SUCCESS);
3413 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3414 IN PLARGE_INTEGER NewFileSize)
3422 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3429 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3430 IN MMFLUSH_TYPE FlushType)
3437 MmForceSectionClosed (DWORD Unknown0,
3446 MmMapViewInSystemSpace (IN PVOID Section,
3447 OUT PVOID * MappedBase,
3451 return (STATUS_NOT_IMPLEMENTED);
3455 MmUnmapViewInSystemSpace (DWORD Unknown0)
3458 return (STATUS_NOT_IMPLEMENTED);
3463 MmSetBankedSection (DWORD Unknown0,
3471 return (STATUS_NOT_IMPLEMENTED);
3475 /**********************************************************************
3480 * Creates a section object.
3483 * SectionObjiect (OUT)
3484 * Caller supplied storage for the resulting pointer
3485 * to a SECTION_BOJECT instance;
3488 * Specifies the desired access to the section can be a
3490 * STANDARD_RIGHTS_REQUIRED |
3492 * SECTION_MAP_WRITE |
3493 * SECTION_MAP_READ |
3494 * SECTION_MAP_EXECUTE
3496 * ObjectAttributes [OPTIONAL]
3497 * Initialized attributes for the object can be used
3498 * to create a named section;
3501 * Maximizes the size of the memory section. Must be
3502 * non-NULL for a page-file backed section.
3503 * If value specified for a mapped file and the file is
3504 * not large enough, file will be extended.
3506 * SectionPageProtection
3507 * Can be a combination of:
3513 * AllocationAttributes
3514 * Can be a combination of:
3519 * Handle to a file to create a section mapped to a file
3520 * instead of a memory backed section;
3529 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
3530 IN ACCESS_MASK DesiredAccess,
3531 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3532 IN PLARGE_INTEGER MaximumSize,
3533 IN ULONG SectionPageProtection,
3534 IN ULONG AllocationAttributes,
3535 IN HANDLE FileHandle OPTIONAL,
3536 IN PFILE_OBJECT File OPTIONAL)
3538 return (STATUS_NOT_IMPLEMENTED);