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.
324 PCACHE_SEGMENT CacheSeg;
325 PFILE_OBJECT FileObject;
327 PREACTOS_COMMON_FCB_HEADER Fcb;
329 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
330 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
333 * If the file system is letting us go directly to the cache and the
334 * memory area was mapped at an offset in the file which is page aligned
335 * then get the related cache segment.
337 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
338 (Offset->QuadPart % PAGE_SIZE) == 0)
340 PHYSICAL_ADDRESS Addr;
343 * Get the related cache segment; we use a lower level interface than
344 * filesystems do because it is safe for us to use an offset with a
345 * alignment less than the file system block size.
347 Status = CcRosGetCacheSegment(Fcb->Bcb,
353 if (!NT_SUCCESS(Status))
360 * If the cache segment isn't up to date then call the file
361 * system to read in the data.
363 Status = ReadCacheSegment(CacheSeg);
364 if (!NT_SUCCESS(Status))
366 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, FALSE, FALSE, FALSE);
371 * Retrieve the page from the cache segment that we actually want.
373 Addr = MmGetPhysicalAddress(BaseAddress +
374 Offset->u.LowPart - BaseOffset);
376 MmReferencePage((*Page));
378 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, TRUE, FALSE, TRUE);
385 * Allocate a page, this is rather complicated by the possibility
386 * we might have to move other things out of memory
388 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, Page);
389 if (!NT_SUCCESS(Status))
394 Status = CcRosGetCacheSegment(Fcb->Bcb,
400 if (!NT_SUCCESS(Status))
407 * If the cache segment isn't up to date then call the file
408 * system to read in the data.
410 Status = ReadCacheSegment(CacheSeg);
411 if (!NT_SUCCESS(Status))
413 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, FALSE, FALSE, FALSE);
417 PageAddr = ExAllocatePageWithPhysPage(*Page);
418 OffsetInPage = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - Offset->u.LowPart;
419 if (OffsetInPage >= PAGE_SIZE)
421 memcpy(PageAddr, BaseAddress + Offset->u.LowPart - BaseOffset, PAGE_SIZE);
425 memcpy(PageAddr, BaseAddress + Offset->u.LowPart - BaseOffset, OffsetInPage);
426 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, TRUE, FALSE, FALSE);
427 Status = CcRosGetCacheSegment(Fcb->Bcb,
428 Offset->u.LowPart + OffsetInPage,
433 if (!NT_SUCCESS(Status))
435 ExUnmapPage(PageAddr);
441 * If the cache segment isn't up to date then call the file
442 * system to read in the data.
444 Status = ReadCacheSegment(CacheSeg);
445 if (!NT_SUCCESS(Status))
447 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, FALSE, FALSE, FALSE);
448 ExUnmapPage(PageAddr);
452 memcpy(PageAddr + OffsetInPage, BaseAddress, PAGE_SIZE - OffsetInPage);
454 CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, TRUE, FALSE, FALSE);
455 ExUnmapPage(PageAddr);
457 return(STATUS_SUCCESS);
461 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace,
462 MEMORY_AREA* MemoryArea,
466 LARGE_INTEGER Offset;
470 PSECTION_OBJECT Section;
471 PMM_SECTION_SEGMENT Segment;
479 * There is a window between taking the page fault and locking the
480 * address space when another thread could load the page so we check
483 if (MmIsPagePresent(NULL, Address))
487 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
489 return(STATUS_SUCCESS);
492 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
493 Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) +
494 MemoryArea->Data.SectionData.ViewOffset;
499 Segment = MemoryArea->Data.SectionData.Segment;
500 Section = MemoryArea->Data.SectionData.Section;
501 Region = MmFindRegion(MemoryArea->BaseAddress,
502 &MemoryArea->Data.SectionData.RegionListHead,
504 MmLockSection(Section);
505 MmLockSectionSegment(Segment);
508 * Check if this page needs to be mapped COW
510 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
511 (Region->Protect == PAGE_READWRITE ||
512 Region->Protect == PAGE_EXECUTE_READWRITE))
514 Attributes = PAGE_READONLY;
518 Attributes = Region->Protect;
522 * Get or create a page operation descriptor
524 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart,
528 DPRINT1("MmGetPageOp failed\n");
533 * Check if someone else is already handling this fault, if so wait
536 if (PageOp->Thread != PsGetCurrentThread())
538 MmUnlockSectionSegment(Segment);
539 MmUnlockSection(Section);
540 MmUnlockAddressSpace(AddressSpace);
541 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
547 * Check for various strange conditions
549 if (Status != STATUS_SUCCESS)
551 DPRINT1("Failed to wait for page op\n");
554 if (PageOp->Status == STATUS_PENDING)
556 DPRINT1("Woke for page op before completion\n");
560 * If this wasn't a pagein then restart the operation
562 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
564 MmLockAddressSpace(AddressSpace);
565 MmReleasePageOp(PageOp);
566 DPRINT("Address 0x%.8X\n", Address);
567 return(STATUS_MM_RESTART_OPERATION);
570 * If the thread handling this fault has failed then we don't retry
572 if (!NT_SUCCESS(PageOp->Status))
574 MmLockAddressSpace(AddressSpace);
575 DPRINT("Address 0x%.8X\n", Address);
576 return(PageOp->Status);
578 MmLockAddressSpace(AddressSpace);
579 MmLockSection(Section);
580 MmLockSectionSegment(Segment);
582 * If the completed fault was for another address space then set the
585 if (!MmIsPagePresent(NULL, Address))
587 Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart);
590 MmUnlockSectionSegment(Segment);
591 MmUnlockSection(Section);
592 MmReleasePageOp(PageOp);
593 return(STATUS_MM_RESTART_OPERATION);
596 Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry));
597 MmReferencePage(Page);
598 MmSharePageEntrySectionSegment(Segment, Offset.u.LowPart);
600 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
602 MemoryArea->Attributes,
605 if (!NT_SUCCESS(Status))
607 DbgPrint("Unable to create virtual mapping\n");
610 MmInsertRmap(Page, PsGetCurrentProcess(),
611 (PVOID)PAGE_ROUND_DOWN(Address));
615 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
617 MmUnlockSectionSegment(Segment);
618 MmUnlockSection(Section);
619 MmReleasePageOp(PageOp);
620 DPRINT("Address 0x%.8X\n", Address);
621 return(STATUS_SUCCESS);
625 * Must be private page we have swapped out.
627 if (MmIsPageSwapEntry(NULL, (PVOID)PAddress))
632 MmUnlockSectionSegment(Segment);
633 MmUnlockSection(Section);
635 MmDeletePageFileMapping(NULL, (PVOID)PAddress, &SwapEntry);
637 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
638 if (!NT_SUCCESS(Status))
643 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
644 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
645 Status = MmReadFromSwapPage(SwapEntry, Mdl);
646 if (!NT_SUCCESS(Status))
651 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
656 while (Status == STATUS_NO_MEMORY)
658 MmUnlockAddressSpace(AddressSpace);
659 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
664 MmLockAddressSpace(AddressSpace);
666 if (!NT_SUCCESS(Status))
668 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
674 * Store the swap entry for later use.
676 MmSetSavedSwapEntryPage(Page, SwapEntry);
679 * Add the page to the process's working set
681 MmInsertRmap(Page, PsGetCurrentProcess(),
682 (PVOID)PAGE_ROUND_DOWN(Address));
685 * Finish the operation
689 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
691 PageOp->Status = STATUS_SUCCESS;
692 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
693 MmReleasePageOp(PageOp);
694 DPRINT("Address 0x%.8X\n", Address);
695 return(STATUS_SUCCESS);
699 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
701 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
704 * Just map the desired physical page
706 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
712 * Don't add an rmap entry since the page mapped could be for
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 * Map anonymous memory for BSS sections
735 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS)
737 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
738 if (!NT_SUCCESS(Status))
740 MmUnlockSectionSegment(Segment);
741 MmUnlockSection(Section);
742 MmUnlockAddressSpace(AddressSpace);
743 MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
744 MmLockAddressSpace(AddressSpace);
745 MmLockSection(Section);
746 MmLockSectionSegment(Segment);
749 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
754 MmInsertRmap(Page, PsGetCurrentProcess(),
755 (PVOID)PAGE_ROUND_DOWN(Address));
758 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
762 * Cleanup and release locks
764 PageOp->Status = STATUS_SUCCESS;
765 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
766 MmReleasePageOp(PageOp);
767 MmUnlockSectionSegment(Segment);
768 MmUnlockSection(Section);
769 DPRINT("Address 0x%.8X\n", Address);
770 return(STATUS_SUCCESS);
774 * Get the entry corresponding to the offset within the section
776 Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart);
781 * If the entry is zero (and it can't change because we have
782 * locked the segment) then we need to load the page.
786 * Release all our locks and read in the page from disk
788 MmUnlockSectionSegment(Segment);
789 MmUnlockSection(Section);
790 MmUnlockAddressSpace(AddressSpace);
792 if (Segment->Flags & MM_PAGEFILE_SEGMENT)
794 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
798 Status = MiReadPage(MemoryArea, &Offset, &Page);
800 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
803 * FIXME: What do we know in this case?
805 DPRINT1("IoPageRead failed (Status %x)\n", Status);
808 * Cleanup and release locks
810 PageOp->Status = Status;
811 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
812 MmReleasePageOp(PageOp);
813 MmLockAddressSpace(AddressSpace);
818 * Relock the address space, section and segment
820 MmLockAddressSpace(AddressSpace);
821 MmLockSection(Section);
822 MmLockSectionSegment(Segment);
825 * Check the entry. No one should change the status of a page
826 * that has a pending page-in.
828 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
831 DbgPrint("Someone changed ppte entry while we slept\n");
836 * Mark the offset within the section as having valid, in-memory
839 Entry = Page.u.LowPart;
840 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
841 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
843 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
848 if (!NT_SUCCESS(Status))
850 MmUnlockSectionSegment(Segment);
851 MmUnlockSection(Section);
852 MmUnlockAddressSpace(AddressSpace);
853 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
858 if (!NT_SUCCESS(Status))
862 MmLockAddressSpace(AddressSpace);
863 MmLockSection(Section);
864 MmLockSectionSegment(Segment);
866 MmInsertRmap(Page, PsGetCurrentProcess(),
867 (PVOID)PAGE_ROUND_DOWN(Address));
868 if (!NT_SUCCESS(Status))
870 DbgPrint("Unable to create virtual mapping\n");
875 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
877 PageOp->Status = STATUS_SUCCESS;
878 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
879 MmReleasePageOp(PageOp);
880 MmUnlockSectionSegment(Segment);
881 MmUnlockSection(Section);
882 DPRINT("MmNotPresentFaultSectionView succeeded\n");
883 return(STATUS_SUCCESS);
885 else if (IS_SWAP_FROM_SSE(Entry))
890 SwapEntry = SWAPENTRY_FROM_SSE(Entry);
893 * Release all our locks and read in the page from disk
895 MmUnlockSectionSegment(Segment);
896 MmUnlockSection(Section);
897 MmUnlockAddressSpace(AddressSpace);
899 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
900 if (!NT_SUCCESS(Status))
905 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
906 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
907 Status = MmReadFromSwapPage(SwapEntry, Mdl);
908 if (!NT_SUCCESS(Status))
914 * Relock the address space, section and segment
916 MmLockAddressSpace(AddressSpace);
917 MmLockSection(Section);
918 MmLockSectionSegment(Segment);
921 * Check the entry. No one should change the status of a page
922 * that has a pending page-in.
924 Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
927 DbgPrint("Someone changed ppte entry while we slept\n");
932 * Mark the offset within the section as having valid, in-memory
935 Entry = Page.u.LowPart;
936 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
937 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
940 * Save the swap entry.
942 MmSetSavedSwapEntryPage(Page, SwapEntry);
944 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
949 MmInsertRmap(Page, PsGetCurrentProcess(),
950 (PVOID)PAGE_ROUND_DOWN(Address));
951 if (!NT_SUCCESS(Status))
953 DbgPrint("Unable to create virtual mapping\n");
958 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
960 PageOp->Status = STATUS_SUCCESS;
961 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
962 MmReleasePageOp(PageOp);
963 MmUnlockSectionSegment(Segment);
964 MmUnlockSection(Section);
965 DPRINT("MmNotPresentFaultSectionView succeeded\n");
966 return(STATUS_SUCCESS);
971 * If the section offset is already in-memory and valid then just
972 * take another reference to the page
975 Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry);
976 MmReferencePage(Page);
977 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
979 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
984 MmInsertRmap(Page, PsGetCurrentProcess(),
985 (PVOID)PAGE_ROUND_DOWN(Address));
986 if (!NT_SUCCESS(Status))
988 DbgPrint("Unable to create virtual mapping\n");
993 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
995 PageOp->Status = STATUS_SUCCESS;
996 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
997 MmReleasePageOp(PageOp);
998 MmUnlockSectionSegment(Segment);
999 MmUnlockSection(Section);
1000 return(STATUS_SUCCESS);
1005 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace,
1006 MEMORY_AREA* MemoryArea,
1010 PMM_SECTION_SEGMENT Segment;
1011 PSECTION_OBJECT Section;
1012 PHYSICAL_ADDRESS OldPage;
1013 PHYSICAL_ADDRESS NewPage;
1017 LARGE_INTEGER Offset;
1022 * Check if the page has been paged out or has already been set readwrite
1024 if (!MmIsPagePresent(NULL, Address) ||
1025 MmGetPageProtect(NULL, Address) & PAGE_READWRITE)
1027 return(STATUS_SUCCESS);
1031 * Find the offset of the page
1033 PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address));
1034 Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) +
1035 MemoryArea->Data.SectionData.ViewOffset;
1040 Segment = MemoryArea->Data.SectionData.Segment;
1041 Section = MemoryArea->Data.SectionData.Section;
1042 Region = MmFindRegion(MemoryArea->BaseAddress,
1043 &MemoryArea->Data.SectionData.RegionListHead,
1045 MmLockSection(Section);
1046 MmLockSectionSegment(Segment);
1051 if (MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) == 0)
1053 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1058 * Check if we are doing COW
1060 if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1061 (Region->Protect == PAGE_READWRITE ||
1062 Region->Protect == PAGE_EXECUTE_READWRITE)))
1064 MmUnlockSection(Section);
1065 MmUnlockSectionSegment(Segment);
1066 return(STATUS_UNSUCCESSFUL);
1070 * Get or create a pageop
1072 PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart,
1073 MM_PAGEOP_ACCESSFAULT);
1076 DPRINT1("MmGetPageOp failed\n");
1081 * Wait for any other operations to complete
1083 if (PageOp->Thread != PsGetCurrentThread())
1085 MmUnlockSectionSegment(Segment);
1086 MmUnlockSection(Section);
1087 MmUnlockAddressSpace(AddressSpace);
1088 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
1094 * Check for various strange conditions
1096 if (Status != STATUS_SUCCESS)
1098 DPRINT1("Failed to wait for page op\n");
1101 if (PageOp->Status == STATUS_PENDING)
1103 DPRINT1("Woke for page op before completion\n");
1107 * Restart the operation
1109 MmLockAddressSpace(AddressSpace);
1110 MmReleasePageOp(PageOp);
1111 return(STATUS_MM_RESTART_OPERATION);
1115 * Release locks now we have the pageop
1117 MmUnlockSectionSegment(Segment);
1118 MmUnlockSection(Section);
1119 MmUnlockAddressSpace(AddressSpace);
1124 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage);
1129 OldPage = MmGetPhysicalAddressForProcess(NULL, Address);
1131 NewAddress = ExAllocatePageWithPhysPage(NewPage);
1132 memcpy(NewAddress, (PVOID)PAGE_ROUND_DOWN(Address), PAGE_SIZE);
1133 ExUnmapPage(NewAddress);
1136 * Delete the old entry.
1138 MmDeleteVirtualMapping(PsGetCurrentProcess(), Address, FALSE, NULL, NULL);
1141 * Set the PTE to point to the new page
1143 MmLockAddressSpace(AddressSpace);
1144 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
1149 MmInsertRmap(NewPage, PsGetCurrentProcess(),
1150 (PVOID)PAGE_ROUND_DOWN(Address));
1151 if (!NT_SUCCESS(Status))
1153 DbgPrint("Unable to create virtual mapping\n");
1158 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
1162 * Unshare the old page.
1164 MmUnsharePageEntrySectionSegment(Section, Segment, Offset.QuadPart, FALSE);
1165 MmDeleteRmap(OldPage, PsGetCurrentProcess(),
1166 (PVOID)PAGE_ROUND_DOWN(Address));
1167 MmReleasePageMemoryConsumer(MC_USER, OldPage);
1169 PageOp->Status = STATUS_SUCCESS;
1170 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1171 MmReleasePageOp(PageOp);
1172 return(STATUS_SUCCESS);
1176 MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address)
1178 MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
1180 PHYSICAL_ADDRESS PhysicalAddress;
1182 PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
1183 MmDeleteVirtualMapping(Process,
1190 PageOutContext->WasDirty = TRUE;
1192 if (!PageOutContext->Private)
1194 MmUnsharePageEntrySectionSegment(PageOutContext->Section,
1195 PageOutContext->Segment,
1196 PageOutContext->Offset.u.LowPart,
1197 PageOutContext->WasDirty);
1199 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1203 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace,
1204 MEMORY_AREA* MemoryArea,
1208 LARGE_INTEGER Offset;
1209 PSECTION_OBJECT Section;
1210 PMM_SECTION_SEGMENT Segment;
1211 PHYSICAL_ADDRESS PhysicalAddress;
1212 MM_SECTION_PAGEOUT_CONTEXT Context;
1213 SWAPENTRY SwapEntry;
1218 PFILE_OBJECT FileObject;
1219 PREACTOS_COMMON_FCB_HEADER Fcb;
1220 BOOLEAN DirectMapped;
1222 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1224 Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1225 MemoryArea->Data.SectionData.ViewOffset;
1227 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1228 DirectMapped = FALSE;
1229 if (FileObject != NULL)
1231 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
1234 * If the file system is letting us go directly to the cache and the
1235 * memory area was mapped at an offset in the file which is page aligned
1236 * then note this is a direct mapped page.
1238 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1239 (Offset.QuadPart % PAGE_SIZE) == 0)
1241 DirectMapped = TRUE;
1246 * Get the segment and section.
1248 Segment = MemoryArea->Data.SectionData.Segment;
1249 Section = MemoryArea->Data.SectionData.Section;
1252 * This should never happen since mappings of physical memory are never
1253 * placed in the rmap lists.
1255 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1257 DPRINT1("Trying to page out from physical memory section address 0x%X "
1258 "process %d\n", Address, AddressSpace->Process->UniqueProcessId);
1263 * Get the section segment entry and the physical address.
1265 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1266 if (!MmIsPagePresent(AddressSpace->Process, Address))
1268 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1269 AddressSpace->Process->UniqueProcessId, Address);
1273 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1274 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1277 * Prepare the context structure for the rmap delete call.
1279 Context.Section = Section;
1280 Context.Segment = Segment;
1281 Context.Offset = Offset;
1282 Context.WasDirty = FALSE;
1283 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1284 IS_SWAP_FROM_SSE(Entry) ||
1285 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1287 Context.Private = Private = TRUE;
1291 Context.Private = Private = FALSE;
1295 * Take an additional reference to the page.
1297 // MmReferencePage(PhysicalAddress);
1300 * Paging out data mapped read-only is easy.
1302 if (MemoryArea->Attributes & PAGE_READONLY ||
1303 MemoryArea->Attributes & PAGE_EXECUTE_READ)
1306 * Read-only data should never be in the swapfile.
1310 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1311 "paddress 0x%.8X\n", SwapEntry, Address,
1317 * Read-only data should never be COWed
1321 DPRINT1("Had private copy of read-only page.\n");
1326 * Delete all mappings of this page.
1328 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context,
1329 MmPageOutDeleteMapping);
1330 if (Context.WasDirty)
1335 * If this page wasn't direct mapped then we have a private copy so
1336 * release back to the system; otherwise the cache manager will have
1337 * handled freeing the cache segment which we mapped from.
1341 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1344 PageOp->Status = STATUS_SUCCESS;
1345 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1346 MmReleasePageOp(PageOp);
1347 return(STATUS_SUCCESS);
1351 * Otherwise we have read-write data.
1353 MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping);
1356 * If this wasn't a private page then we should have reduced the entry to
1357 * zero by deleting all the rmaps.
1359 if (!Private && MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) != 0)
1365 * If the page wasn't dirty then we can just free it as for a readonly page.
1366 * Since we unmapped all the mappings above we know it will not suddenly
1369 if (!Context.WasDirty)
1371 if (!DirectMapped || Private)
1373 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1374 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1378 if (!(Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) &&
1381 DPRINT1("Private page, non-dirty but not swapped out "
1382 "process %d address 0x%.8X\n",
1383 AddressSpace->Process->UniqueProcessId,
1389 Status = MmCreatePageFileMapping(AddressSpace->Process,
1392 if (!NT_SUCCESS(Status))
1399 PageOp->Status = STATUS_SUCCESS;
1400 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1401 MmReleasePageOp(PageOp);
1402 return(STATUS_SUCCESS);
1406 * If this page was direct mapped from the cache then the cache manager
1407 * will already have taken care of writing it back.
1409 if (DirectMapped && !Private)
1411 assert(SwapEntry == 0);
1412 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1413 PageOp->Status = STATUS_SUCCESS;
1414 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1415 MmReleasePageOp(PageOp);
1416 return(STATUS_SUCCESS);
1420 * If necessary, allocate an entry in the paging file for this page
1422 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1425 SwapEntry = MmAllocSwapPage();
1428 MmShowOutOfSpaceMessagePagingFile();
1431 * For private pages restore the old mappings.
1435 Status = MmCreateVirtualMapping(MemoryArea->Process,
1437 MemoryArea->Attributes,
1440 MmSetDirtyPage(MemoryArea->Process, Address);
1441 MmInsertRmap(PhysicalAddress,
1442 MemoryArea->Process,
1448 * For non-private pages if the page wasn't direct mapped then
1449 * set it back into the section segment entry so we don't loose
1450 * our copy. Otherwise it will be handled by the cache manager.
1452 Status = MmCreateVirtualMapping(MemoryArea->Process,
1454 MemoryArea->Attributes,
1457 MmSetDirtyPage(MemoryArea->Process, Address);
1458 MmInsertRmap(PhysicalAddress,
1459 MemoryArea->Process,
1461 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart,
1462 PhysicalAddress.u.LowPart);
1463 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
1465 PageOp->Status = STATUS_UNSUCCESSFUL;
1466 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1467 MmReleasePageOp(PageOp);
1468 return(STATUS_UNSUCCESSFUL);
1473 * Write the page to the pagefile
1475 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1476 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1477 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1478 if (!NT_SUCCESS(Status))
1480 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1483 * As above: undo our actions.
1484 * FIXME: Also free the swap page.
1488 Status = MmCreateVirtualMapping(MemoryArea->Process,
1490 MemoryArea->Attributes,
1493 MmSetDirtyPage(MemoryArea->Process, Address);
1494 MmInsertRmap(PhysicalAddress,
1495 MemoryArea->Process,
1500 Status = MmCreateVirtualMapping(MemoryArea->Process,
1502 MemoryArea->Attributes,
1505 MmSetDirtyPage(MemoryArea->Process, Address);
1506 MmInsertRmap(PhysicalAddress,
1507 MemoryArea->Process,
1509 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart,
1510 PhysicalAddress.u.LowPart);
1511 MmSharePageEntrySectionSegment(Segment, Offset.QuadPart);
1513 PageOp->Status = STATUS_UNSUCCESSFUL;
1514 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1515 MmReleasePageOp(PageOp);
1516 return(STATUS_UNSUCCESSFUL);
1520 * Otherwise we have succeeded.
1522 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1523 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
1524 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
1528 Status = MmCreatePageFileMapping(MemoryArea->Process,
1531 if (!NT_SUCCESS(Status))
1538 Entry = MAKE_SWAP_SSE(SwapEntry);
1539 MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry);
1542 PageOp->Status = STATUS_SUCCESS;
1543 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1544 MmReleasePageOp(PageOp);
1545 return(STATUS_SUCCESS);
1549 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace,
1550 PMEMORY_AREA MemoryArea,
1554 LARGE_INTEGER Offset;
1555 PSECTION_OBJECT Section;
1556 PMM_SECTION_SEGMENT Segment;
1557 PHYSICAL_ADDRESS PhysicalAddress;
1558 SWAPENTRY SwapEntry;
1563 PFILE_OBJECT FileObject;
1564 PREACTOS_COMMON_FCB_HEADER Fcb = NULL;
1565 BOOLEAN DirectMapped;
1567 Address = (PVOID)PAGE_ROUND_DOWN(Address);
1569 Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1570 MemoryArea->Data.SectionData.ViewOffset;
1572 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
1573 DirectMapped = FALSE;
1574 if (FileObject != NULL)
1576 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
1579 * If the file system is letting us go directly to the cache and the
1580 * memory area was mapped at an offset in the file which is page aligned
1581 * then note this is a direct mapped page.
1583 if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ &&
1584 (Offset.QuadPart % PAGE_SIZE) == 0)
1586 DirectMapped = TRUE;
1591 * Get the segment and section.
1593 Segment = MemoryArea->Data.SectionData.Segment;
1594 Section = MemoryArea->Data.SectionData.Section;
1597 * This should never happen since mappings of physical memory are never
1598 * placed in the rmap lists.
1600 if (Section->AllocationAttributes & SEC_PHYSICALMEMORY)
1602 DPRINT1("Trying to write back page from physical memory mapped at %X "
1603 "process %d\n", Address, AddressSpace->Process->UniqueProcessId);
1608 * Get the section segment entry and the physical address.
1610 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1611 if (!MmIsPagePresent(AddressSpace->Process, Address))
1613 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1614 AddressSpace->Process->UniqueProcessId, Address);
1618 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1619 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1622 * Check for a private (COWed) page.
1624 if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1625 IS_SWAP_FROM_SSE(Entry) ||
1626 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)
1636 * Speculatively set all mappings of the page to clean.
1638 MmSetCleanAllRmaps(PhysicalAddress);
1641 * If this page was direct mapped from the cache then the cache manager
1642 * will take care of writing it back to disk.
1644 if (DirectMapped && !Private)
1646 assert(SwapEntry == 0);
1647 CcRosMarkDirtyCacheSegment(Fcb->Bcb, Offset.u.LowPart);
1648 PageOp->Status = STATUS_SUCCESS;
1649 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1650 MmReleasePageOp(PageOp);
1651 return(STATUS_SUCCESS);
1655 * If necessary, allocate an entry in the paging file for this page
1657 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
1660 SwapEntry = MmAllocSwapPage();
1663 MmSetDirtyAllRmaps(PhysicalAddress);
1664 PageOp->Status = STATUS_UNSUCCESSFUL;
1665 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1666 MmReleasePageOp(PageOp);
1667 return(STATUS_UNSUCCESSFUL);
1672 * Write the page to the pagefile
1674 Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE);
1675 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
1676 Status = MmWriteToSwapPage(SwapEntry, Mdl);
1677 if (!NT_SUCCESS(Status))
1679 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1681 MmSetDirtyAllRmaps(PhysicalAddress);
1682 PageOp->Status = STATUS_UNSUCCESSFUL;
1683 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1684 MmReleasePageOp(PageOp);
1685 return(STATUS_UNSUCCESSFUL);
1689 * Otherwise we have succeeded.
1691 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress);
1692 MmSetSavedSwapEntryPage(PhysicalAddress, SwapEntry);
1693 PageOp->Status = STATUS_SUCCESS;
1694 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
1695 MmReleasePageOp(PageOp);
1696 return(STATUS_SUCCESS);
1700 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace,
1708 PMEMORY_AREA MemoryArea;
1709 PMM_SECTION_SEGMENT Segment;
1713 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
1714 Segment = MemoryArea->Data.SectionData.Segment;
1716 if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) &&
1717 (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE))
1722 if (OldProtect != NewProtect)
1724 for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
1726 PVOID Address = BaseAddress + (i * PAGE_SIZE);
1727 ULONG Protect = NewProtect;
1730 * If we doing COW for this segment then check if the page is
1733 if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address))
1735 LARGE_INTEGER Offset;
1737 LARGE_INTEGER PhysicalAddress;
1740 (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) +
1741 MemoryArea->Data.SectionData.ViewOffset;
1742 Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart);
1744 MmGetPhysicalAddressForProcess(AddressSpace->Process, Address);
1746 Protect = PAGE_READONLY;
1747 if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS ||
1748 IS_SWAP_FROM_SSE(Entry) ||
1749 (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart))
1751 Protect = NewProtect;
1755 if (MmIsPagePresent(AddressSpace->Process, Address))
1757 MmSetPageProtect(AddressSpace->Process, BaseAddress,
1765 MmProtectSectionView(PMADDRESS_SPACE AddressSpace,
1766 PMEMORY_AREA MemoryArea,
1776 min(Length, MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress);
1777 Region = MmFindRegion(MemoryArea->BaseAddress,
1778 &MemoryArea->Data.SectionData.RegionListHead,
1780 *OldProtect = Region->Protect;
1781 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
1782 &MemoryArea->Data.SectionData.RegionListHead,
1783 BaseAddress, Length, Region->Type, Protect,
1784 MmAlterViewAttributes);
1790 MmQuerySectionView(PMEMORY_AREA MemoryArea,
1792 PMEMORY_BASIC_INFORMATION Info,
1793 PULONG ResultLength)
1796 PVOID RegionBaseAddress;
1798 Region = MmFindRegion(MemoryArea->BaseAddress,
1799 &MemoryArea->Data.SectionData.RegionListHead,
1800 Address, &RegionBaseAddress);
1801 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
1802 Info->AllocationBase = MemoryArea->BaseAddress;
1803 Info->AllocationProtect = MemoryArea->Attributes;
1804 Info->RegionSize = MemoryArea->Length;
1805 Info->State = MEM_COMMIT;
1806 Info->Protect = Region->Protect;
1807 if (MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE)
1809 Info->Type = MEM_IMAGE;
1813 Info->Type = MEM_MAPPED;
1816 return(STATUS_SUCCESS);
1820 MmpDeleteSection(PVOID ObjectBody)
1822 PSECTION_OBJECT Section = (PSECTION_OBJECT)ObjectBody;
1824 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody);
1825 if (Section->AllocationAttributes & SEC_IMAGE)
1829 for (i = 0; i < Section->NrSegments; i++)
1831 InterlockedDecrement(&Section->Segments[i].ReferenceCount);
1836 InterlockedDecrement(&Section->Segments->ReferenceCount);
1838 if (Section->FileObject != NULL)
1840 CcRosDereferenceCache(Section->FileObject);
1841 ObDereferenceObject(Section->FileObject);
1842 Section->FileObject = NULL;
1847 MmpCloseSection(PVOID ObjectBody,
1850 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
1851 ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody));
1856 MmpCreateSection(PVOID ObjectBody,
1858 PWSTR RemainingPath,
1859 POBJECT_ATTRIBUTES ObjectAttributes)
1861 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
1862 ObjectBody, Parent, RemainingPath);
1864 if (RemainingPath == NULL)
1866 return(STATUS_SUCCESS);
1869 if (wcschr(RemainingPath+1, L'\\') != NULL)
1871 return(STATUS_UNSUCCESSFUL);
1874 return(STATUS_SUCCESS);
1878 MmCreatePhysicalMemorySection(VOID)
1880 HANDLE PhysSectionH;
1881 PSECTION_OBJECT PhysSection;
1883 OBJECT_ATTRIBUTES Obj;
1884 UNICODE_STRING Name = UNICODE_STRING_INITIALIZER(L"\\Device\\PhysicalMemory");
1885 LARGE_INTEGER SectionSize;
1888 * Create the section mapping physical memory
1890 SectionSize.QuadPart = 0xFFFFFFFF;
1891 InitializeObjectAttributes(&Obj,
1896 Status = NtCreateSection(&PhysSectionH,
1900 PAGE_EXECUTE_READWRITE,
1903 if (!NT_SUCCESS(Status))
1905 DbgPrint("Failed to create PhysicalMemory section\n");
1908 Status = ObReferenceObjectByHandle(PhysSectionH,
1912 (PVOID*)&PhysSection,
1914 if (!NT_SUCCESS(Status))
1916 DbgPrint("Failed to reference PhysicalMemory section\n");
1919 PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY;
1920 ObDereferenceObject((PVOID)PhysSection);
1922 return(STATUS_SUCCESS);
1926 MmInitSectionImplementation(VOID)
1928 MmSectionObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
1930 RtlInitUnicodeStringFromLiteral(&MmSectionObjectType->TypeName, L"Section");
1932 MmSectionObjectType->Tag = TAG('S', 'E', 'C', 'T');
1933 MmSectionObjectType->TotalObjects = 0;
1934 MmSectionObjectType->TotalHandles = 0;
1935 MmSectionObjectType->MaxObjects = ULONG_MAX;
1936 MmSectionObjectType->MaxHandles = ULONG_MAX;
1937 MmSectionObjectType->PagedPoolCharge = 0;
1938 MmSectionObjectType->NonpagedPoolCharge = sizeof(SECTION_OBJECT);
1939 MmSectionObjectType->Mapping = &MmpSectionMapping;
1940 MmSectionObjectType->Dump = NULL;
1941 MmSectionObjectType->Open = NULL;
1942 MmSectionObjectType->Close = MmpCloseSection;
1943 MmSectionObjectType->Delete = MmpDeleteSection;
1944 MmSectionObjectType->Parse = NULL;
1945 MmSectionObjectType->Security = NULL;
1946 MmSectionObjectType->QueryName = NULL;
1947 MmSectionObjectType->OkayToClose = NULL;
1948 MmSectionObjectType->Create = MmpCreateSection;
1949 MmSectionObjectType->DuplicationNotify = NULL;
1951 return(STATUS_SUCCESS);
1955 MmCreatePageFileSection(PHANDLE SectionHandle,
1956 ACCESS_MASK DesiredAccess,
1957 POBJECT_ATTRIBUTES ObjectAttributes,
1958 PLARGE_INTEGER UMaximumSize,
1959 ULONG SectionPageProtection,
1960 ULONG AllocationAttributes)
1962 * Create a section which is backed by the pagefile
1965 LARGE_INTEGER MaximumSize;
1966 PSECTION_OBJECT Section;
1967 PMM_SECTION_SEGMENT Segment;
1970 if (UMaximumSize == NULL)
1972 return(STATUS_UNSUCCESSFUL);
1974 MaximumSize = *UMaximumSize;
1977 * Check the protection
1979 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
1980 SectionPageProtection)
1982 return(STATUS_INVALID_PAGE_PROTECTION);
1986 * Create the section
1988 Status = ObCreateObject(SectionHandle,
1991 MmSectionObjectType,
1993 if (!NT_SUCCESS(Status))
2001 Section->SectionPageProtection = SectionPageProtection;
2002 Section->AllocationAttributes = AllocationAttributes;
2003 InitializeListHead(&Section->ViewListHead);
2004 KeInitializeSpinLock(&Section->ViewListLock);
2005 KeInitializeMutex(&Section->Lock, 0);
2006 Section->FileObject = NULL;
2007 Section->MaximumSize = MaximumSize;
2008 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2009 TAG_MM_SECTION_SEGMENT);
2010 if (Segment == NULL)
2012 ZwClose(*SectionHandle);
2013 ObDereferenceObject(Section);
2014 return(STATUS_NO_MEMORY);
2016 Section->Segments = Segment;
2017 Segment->ReferenceCount = 1;
2018 KeInitializeMutex(&Segment->Lock, 0);
2019 Segment->FileOffset = 0;
2020 Segment->Protection = SectionPageProtection;
2021 Segment->Attributes = AllocationAttributes;
2022 Segment->Length = MaximumSize.u.LowPart;
2023 Segment->Flags = MM_PAGEFILE_SEGMENT;
2024 Segment->WriteCopy = FALSE;
2025 return(STATUS_SUCCESS);
2030 MmCreateDataFileSection(PHANDLE SectionHandle,
2031 ACCESS_MASK DesiredAccess,
2032 POBJECT_ATTRIBUTES ObjectAttributes,
2033 PLARGE_INTEGER UMaximumSize,
2034 ULONG SectionPageProtection,
2035 ULONG AllocationAttributes,
2038 * Create a section backed by a data file
2041 PSECTION_OBJECT Section;
2043 LARGE_INTEGER MaximumSize;
2044 PFILE_OBJECT FileObject;
2045 PMM_SECTION_SEGMENT Segment;
2049 * Check the protection
2051 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2052 SectionPageProtection)
2054 return(STATUS_INVALID_PAGE_PROTECTION);
2058 * Create the section
2060 Status = ObCreateObject(SectionHandle,
2063 MmSectionObjectType,
2065 if (!NT_SUCCESS(Status))
2073 Section->SectionPageProtection = SectionPageProtection;
2074 Section->AllocationAttributes = AllocationAttributes;
2075 InitializeListHead(&Section->ViewListHead);
2076 KeInitializeSpinLock(&Section->ViewListLock);
2077 KeInitializeMutex(&Section->Lock, 0);
2078 Section->NrSegments = 1;
2079 Section->ImageBase = NULL;
2080 Section->EntryPoint = NULL;
2081 Section->StackReserve = 0;
2082 Section->StackCommit = 0;
2083 Section->Subsystem = 0;
2084 Section->MinorSubsystemVersion = 0;
2085 Section->MajorSubsystemVersion = 0;
2086 Section->ImageCharacteristics = 0;
2087 Section->Machine = 0;
2088 Section->Executable = FALSE;
2091 * Check file access required
2093 if (SectionPageProtection & PAGE_READWRITE ||
2094 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2096 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2100 FileAccess = FILE_READ_DATA;
2104 * Reference the file handle
2106 Status = ObReferenceObjectByHandle(FileHandle,
2110 (PVOID*)&FileObject,
2112 if (!NT_SUCCESS(Status))
2114 ZwClose(*SectionHandle);
2115 ObDereferenceObject(Section);
2120 * We can't do memory mappings if the file system doesn't support the
2123 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2125 ZwClose(*SectionHandle);
2126 ObDereferenceObject(Section);
2127 ObDereferenceObject(FileObject);
2128 return(STATUS_INVALID_FILE_FOR_SECTION);
2132 * FIXME: Revise this once a locking order for file size changes is
2135 if (UMaximumSize != NULL)
2137 MaximumSize = *UMaximumSize;
2142 ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize;
2145 if (MaximumSize.QuadPart >
2146 ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart)
2148 IO_STATUS_BLOCK Iosb;
2149 Status = NtSetInformationFile(FileHandle,
2152 sizeof(LARGE_INTEGER),
2153 FileAllocationInformation);
2154 if (!NT_SUCCESS(Status))
2156 ZwClose(*SectionHandle);
2157 ObDereferenceObject(Section);
2158 ObDereferenceObject(FileObject);
2159 return(STATUS_SECTION_NOT_EXTENDED);
2166 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2171 if (Status != STATUS_SUCCESS)
2173 ZwClose(*SectionHandle);
2174 ObDereferenceObject(Section);
2175 ObDereferenceObject(FileObject);
2180 * If this file hasn't been mapped as a data file before then allocate a
2181 * section segment to describe the data file mapping
2183 if (FileObject->SectionObjectPointers->DataSectionObject == NULL)
2185 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT),
2186 TAG_MM_SECTION_SEGMENT);
2187 if (Segment == NULL)
2189 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2190 ZwClose(*SectionHandle);
2191 ObDereferenceObject(Section);
2192 ObDereferenceObject(FileObject);
2193 return(STATUS_NO_MEMORY);
2195 Section->Segments = Segment;
2196 Segment->ReferenceCount = 1;
2197 KeInitializeMutex(&Segment->Lock, 0);
2200 * Set the lock before assigning the segment to the file object
2202 Status = KeWaitForSingleObject((PVOID)&Segment->Lock,
2207 if (Status != STATUS_SUCCESS)
2209 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2210 ExFreePool(Segment);
2211 ZwClose(*SectionHandle);
2212 ObDereferenceObject(Section);
2213 ObDereferenceObject(FileObject);
2216 FileObject->SectionObjectPointers->DataSectionObject = (PVOID)Segment;
2218 Segment->FileOffset = 0;
2219 Segment->Protection = 0;
2220 Segment->Attributes = 0;
2221 Segment->Flags = MM_DATAFILE_SEGMENT;
2222 Segment->Characteristics = 0;
2223 Segment->WriteCopy = FALSE;
2224 if (AllocationAttributes & SEC_RESERVE)
2226 Segment->Length = 0;
2230 Segment->Length = MaximumSize.u.LowPart;
2232 Segment->VirtualAddress = NULL;
2237 * If the file is already mapped as a data file then we may need
2241 (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers->
2243 Section->Segments = Segment;
2244 InterlockedIncrement((PLONG)&Segment->ReferenceCount);
2245 Status = KeWaitForSingleObject((PVOID)&Segment->Lock,
2250 if (Status != STATUS_SUCCESS)
2252 InterlockedDecrement((PLONG)&Segment->ReferenceCount);
2253 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2254 ZwClose(*SectionHandle);
2255 ObDereferenceObject(Section);
2256 ObDereferenceObject(FileObject);
2259 if (MaximumSize.u.LowPart > Segment->Length &&
2260 !(AllocationAttributes & SEC_RESERVE))
2262 Segment->Length = MaximumSize.u.LowPart;
2265 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2266 CcRosReferenceCache(FileObject);
2267 Section->FileObject = FileObject;
2268 Section->MaximumSize = MaximumSize;
2269 KeReleaseMutex(&Segment->Lock, FALSE);
2271 ObDereferenceObject(Section);
2272 return(STATUS_SUCCESS);
2275 static ULONG SectionCharacteristicsToProtect[16] =
2277 PAGE_NOACCESS, // 0 = NONE
2278 PAGE_NOACCESS, // 1 = SHARED
2279 PAGE_EXECUTE, // 2 = EXECUTABLE
2280 PAGE_EXECUTE, // 3 = EXECUTABLE, SHARED
2281 PAGE_READONLY, // 4 = READABLE
2282 PAGE_READONLY, // 5 = READABLE, SHARED
2283 PAGE_EXECUTE_READ, // 6 = READABLE, EXECUTABLE
2284 PAGE_EXECUTE_READ, // 7 = READABLE, EXECUTABLE, SHARED
2285 PAGE_READWRITE, // 8 = WRITABLE
2286 PAGE_READWRITE, // 9 = WRITABLE, SHARED
2287 PAGE_EXECUTE_READWRITE, // 10 = WRITABLE, EXECUTABLE
2288 PAGE_EXECUTE_READWRITE, // 11 = WRITABLE, EXECUTABLE, SHARED
2289 PAGE_READWRITE, // 12 = WRITABLE, READABLE
2290 PAGE_READWRITE, // 13 = WRITABLE, READABLE, SHARED
2291 PAGE_EXECUTE_READWRITE, // 14 = WRITABLE, READABLE, EXECUTABLE,
2292 PAGE_EXECUTE_READWRITE, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2296 MmCreateImageSection(PHANDLE SectionHandle,
2297 ACCESS_MASK DesiredAccess,
2298 POBJECT_ATTRIBUTES ObjectAttributes,
2299 PLARGE_INTEGER UMaximumSize,
2300 ULONG SectionPageProtection,
2301 ULONG AllocationAttributes,
2304 PSECTION_OBJECT Section;
2306 PFILE_OBJECT FileObject;
2308 IMAGE_DOS_HEADER DosHeader;
2309 IO_STATUS_BLOCK Iosb;
2310 LARGE_INTEGER Offset;
2311 IMAGE_NT_HEADERS PEHeader;
2312 PIMAGE_SECTION_HEADER ImageSections;
2313 PMM_SECTION_SEGMENT SectionSegments;
2315 PMM_IMAGE_SECTION_OBJECT ImageSectionObject;
2318 * Check the protection
2320 if ((SectionPageProtection & PAGE_FLAGS_VALID_FROM_USER_MODE) !=
2321 SectionPageProtection)
2323 return(STATUS_INVALID_PAGE_PROTECTION);
2327 * Specifying a maximum size is meaningless for an image section
2329 if (UMaximumSize != NULL)
2331 return(STATUS_INVALID_PARAMETER_4);
2335 * Read the dos header
2337 Offset.QuadPart = 0;
2338 Status = ZwReadFile(FileHandle,
2347 if (!NT_SUCCESS(Status))
2351 if (Iosb.Information != sizeof(DosHeader))
2353 return(STATUS_INVALID_IMAGE_FORMAT);
2357 * Check the DOS signature
2359 if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
2361 return(STATUS_INVALID_IMAGE_FORMAT);
2365 * Read the PE header
2367 Offset.QuadPart = DosHeader.e_lfanew;
2368 Status = ZwReadFile(FileHandle,
2377 if (!NT_SUCCESS(Status))
2381 if (Iosb.Information != sizeof(PEHeader))
2383 return(STATUS_INVALID_IMAGE_FORMAT);
2387 * Check the signature
2389 if (PEHeader.Signature != IMAGE_NT_SIGNATURE)
2391 return(STATUS_INVALID_IMAGE_FORMAT);
2395 * Read in the section headers
2397 Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader);
2399 ExAllocatePool(NonPagedPool,
2400 PEHeader.FileHeader.NumberOfSections *
2401 sizeof(IMAGE_SECTION_HEADER));
2402 Status = ZwReadFile(FileHandle,
2408 PEHeader.FileHeader.NumberOfSections *
2409 sizeof(IMAGE_SECTION_HEADER),
2412 if (!NT_SUCCESS(Status))
2414 ExFreePool(ImageSections);
2417 if (Iosb.Information !=
2418 (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
2420 ExFreePool(ImageSections);
2421 return(STATUS_INVALID_IMAGE_FORMAT);
2425 * Create the section
2427 Status = ObCreateObject(SectionHandle,
2430 MmSectionObjectType,
2432 if (!NT_SUCCESS(Status))
2434 ExFreePool(ImageSections);
2441 Section->SectionPageProtection = SectionPageProtection;
2442 Section->AllocationAttributes = AllocationAttributes;
2443 InitializeListHead(&Section->ViewListHead);
2444 KeInitializeSpinLock(&Section->ViewListLock);
2445 KeInitializeMutex(&Section->Lock, 0);
2446 Section->NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2447 Section->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase;
2448 Section->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint;
2449 Section->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve;
2450 Section->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit;
2451 Section->Subsystem = PEHeader.OptionalHeader.Subsystem;
2452 Section->MinorSubsystemVersion =
2453 PEHeader.OptionalHeader.MinorSubsystemVersion;
2454 Section->MajorSubsystemVersion =
2455 PEHeader.OptionalHeader.MajorSubsystemVersion;
2456 Section->ImageCharacteristics = PEHeader.FileHeader.Characteristics;
2457 Section->Machine = PEHeader.FileHeader.Machine;
2458 Section->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0);
2461 * Check file access required
2463 if (SectionPageProtection & PAGE_READWRITE ||
2464 SectionPageProtection & PAGE_EXECUTE_READWRITE)
2466 FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
2470 FileAccess = FILE_READ_DATA;
2474 * Reference the file handle
2476 Status = ObReferenceObjectByHandle(FileHandle,
2480 (PVOID*)&FileObject,
2482 if (!NT_SUCCESS(Status))
2484 ZwClose(*SectionHandle);
2485 ObDereferenceObject(Section);
2486 ExFreePool(ImageSections);
2491 * We can't do memory mappings if the file system doesn't support the
2494 if (!(FileObject->Flags & FO_FCB_IS_VALID))
2496 ZwClose(*SectionHandle);
2497 ObDereferenceObject(Section);
2498 ObDereferenceObject(FileObject);
2499 ExFreePool(ImageSections);
2500 return(STATUS_INVALID_FILE_FOR_SECTION);
2506 Status = KeWaitForSingleObject((PVOID)&FileObject->Lock,
2511 if (Status != STATUS_SUCCESS)
2513 ZwClose(*SectionHandle);
2514 ObDereferenceObject(Section);
2515 ObDereferenceObject(FileObject);
2516 ExFreePool(ImageSections);
2521 * If this file hasn't been mapped as a image file before then allocate the
2522 * section segments to describe the mapping
2524 NrSegments = PEHeader.FileHeader.NumberOfSections + 1;
2525 if (FileObject->SectionObjectPointers->ImageSectionObject == NULL)
2529 ULONG Characteristics;
2531 Size = sizeof(MM_IMAGE_SECTION_OBJECT) +
2532 (sizeof(MM_SECTION_SEGMENT) * NrSegments);
2533 ImageSectionObject =
2534 ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT);
2535 if (ImageSectionObject == NULL)
2537 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2538 ZwClose(*SectionHandle);
2539 ObDereferenceObject(Section);
2540 ObDereferenceObject(FileObject);
2541 ExFreePool(ImageSections);
2542 return(STATUS_NO_MEMORY);
2544 ImageSectionObject->NrSegments = NrSegments;
2545 SectionSegments = ImageSectionObject->Segments;
2546 Section->Segments = SectionSegments;
2548 SectionSegments[0].FileOffset = 0;
2549 SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA;
2550 SectionSegments[0].Protection = PAGE_READWRITE;
2551 SectionSegments[0].RawLength = PAGE_SIZE;
2552 SectionSegments[0].Length = PAGE_SIZE;
2553 SectionSegments[0].Flags = 0;
2554 SectionSegments[0].ReferenceCount = 1;
2555 SectionSegments[0].VirtualAddress = 0;
2556 SectionSegments[0].WriteCopy = TRUE;
2557 KeInitializeMutex(&SectionSegments[0].Lock, 0);
2559 for (i = 1; i < NrSegments; i++)
2561 SectionSegments[i].FileOffset =
2562 ImageSections[i-1].PointerToRawData;
2563 SectionSegments[i].Characteristics =
2564 ImageSections[i-1].Characteristics;
2567 * Set up the protection and write copy variables.
2569 Characteristics = ImageSections[i - 1].Characteristics;
2570 if ((Characteristics & IMAGE_SECTION_CHAR_READABLE) ||
2571 (Characteristics & IMAGE_SECTION_CHAR_WRITABLE) ||
2572 (Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE))
2574 SectionSegments[i].Protection =
2575 SectionCharacteristicsToProtect[Characteristics >> 28];
2576 SectionSegments[i].WriteCopy =
2577 !(Characteristics & IMAGE_SECTION_CHAR_SHARED);
2579 else if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2581 SectionSegments[i].Protection = PAGE_EXECUTE_READ;
2582 SectionSegments[i].WriteCopy = TRUE;
2584 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2586 SectionSegments[i].Protection = PAGE_READWRITE;
2587 SectionSegments[i].WriteCopy = TRUE;
2589 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2591 SectionSegments[i].Protection = PAGE_READWRITE;
2592 SectionSegments[i].WriteCopy = TRUE;
2596 SectionSegments[i].Protection = PAGE_NOACCESS;
2597 SectionSegments[i].WriteCopy = TRUE;
2601 * Set up the attributes.
2603 if (Characteristics & IMAGE_SECTION_CHAR_CODE)
2605 SectionSegments[i].Attributes = 0;
2607 else if (Characteristics & IMAGE_SECTION_CHAR_DATA)
2609 SectionSegments[i].Attributes = 0;
2611 else if (Characteristics & IMAGE_SECTION_CHAR_BSS)
2613 SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS;
2617 SectionSegments[i].Attributes = 0;
2620 SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData;
2621 SectionSegments[i].Length =
2622 ImageSections[i-1].Misc.VirtualSize;
2623 SectionSegments[i].Flags = 0;
2624 SectionSegments[i].ReferenceCount = 1;
2625 SectionSegments[i].VirtualAddress =
2626 (PVOID)ImageSections[i-1].VirtualAddress;
2627 KeInitializeMutex(&SectionSegments[i].Lock, 0);
2630 FileObject->SectionObjectPointers->ImageSectionObject =
2631 (PVOID)ImageSectionObject;
2637 ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)
2638 FileObject->SectionObjectPointers->ImageSectionObject;
2639 SectionSegments = ImageSectionObject->Segments;
2640 Section->Segments = SectionSegments;
2643 * Otherwise just reference all the section segments
2645 for (i = 0; i < NrSegments; i++)
2647 InterlockedIncrement(&SectionSegments[i].ReferenceCount);
2651 ExFreePool(ImageSections);
2652 KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2653 CcRosReferenceCache(FileObject);
2654 Section->FileObject = FileObject;
2656 ObDereferenceObject(Section);
2657 return(STATUS_SUCCESS);
2661 NtCreateSection (OUT PHANDLE SectionHandle,
2662 IN ACCESS_MASK DesiredAccess,
2663 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
2664 IN PLARGE_INTEGER MaximumSize OPTIONAL,
2665 IN ULONG SectionPageProtection OPTIONAL,
2666 IN ULONG AllocationAttributes,
2667 IN HANDLE FileHandle OPTIONAL)
2669 if (AllocationAttributes & SEC_IMAGE)
2671 return(MmCreateImageSection(SectionHandle,
2675 SectionPageProtection,
2676 AllocationAttributes,
2679 else if (FileHandle != NULL)
2681 return(MmCreateDataFileSection(SectionHandle,
2685 SectionPageProtection,
2686 AllocationAttributes,
2691 return(MmCreatePageFileSection(SectionHandle,
2695 SectionPageProtection,
2696 AllocationAttributes));
2701 /**********************************************************************
2720 NtOpenSection(PHANDLE SectionHandle,
2721 ACCESS_MASK DesiredAccess,
2722 POBJECT_ATTRIBUTES ObjectAttributes)
2728 Status = ObOpenObjectByName(ObjectAttributes,
2729 MmSectionObjectType,
2740 MmMapViewOfSegment(PEPROCESS Process,
2741 PMADDRESS_SPACE AddressSpace,
2742 PSECTION_OBJECT Section,
2743 PMM_SECTION_SEGMENT Segment,
2753 Status = MmCreateMemoryArea(Process,
2754 &Process->AddressSpace,
2755 MEMORY_AREA_SECTION_VIEW,
2761 if (!NT_SUCCESS(Status))
2763 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
2764 (*BaseAddress), (*BaseAddress) + ViewSize);
2768 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
2769 InsertTailList(&Section->ViewListHead,
2770 &MArea->Data.SectionData.ViewListEntry);
2771 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
2773 ObReferenceObjectByPointer((PVOID)Section,
2776 ExGetPreviousMode());
2777 MArea->Data.SectionData.Segment = Segment;
2778 MArea->Data.SectionData.Section = Section;
2779 MArea->Data.SectionData.ViewOffset = ViewOffset;
2780 MArea->Data.SectionData.WriteCopyView = FALSE;
2781 MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead,
2782 ViewSize, 0, Protect);
2784 return(STATUS_SUCCESS);
2788 /**********************************************************************
2790 * NtMapViewOfSection
2793 * Maps a view of a section into the virtual address space of a
2798 * Handle of the section.
2801 * Handle of the process.
2804 * Desired base address (or NULL) on entry;
2805 * Actual base address of the view on exit.
2808 * Number of high order address bits that must be zero.
2811 * Size in bytes of the initially committed section of
2815 * Offset in bytes from the beginning of the section
2816 * to the beginning of the view.
2819 * Desired length of map (or zero to map all) on entry
2820 * Actual length mapped on exit.
2822 * InheritDisposition
2823 * Specified how the view is to be shared with
2827 * Type of allocation for the pages.
2830 * Protection for the committed region of the view.
2836 NtMapViewOfSection(HANDLE SectionHandle,
2837 HANDLE ProcessHandle,
2841 PLARGE_INTEGER SectionOffset,
2843 SECTION_INHERIT InheritDisposition,
2844 ULONG AllocationType,
2847 PSECTION_OBJECT Section;
2850 PMADDRESS_SPACE AddressSpace;
2852 Status = ObReferenceObjectByHandle(ProcessHandle,
2853 PROCESS_VM_OPERATION,
2858 if (!NT_SUCCESS(Status))
2863 AddressSpace = &Process->AddressSpace;
2865 Status = ObReferenceObjectByHandle(SectionHandle,
2867 MmSectionObjectType,
2871 if (!(NT_SUCCESS(Status)))
2873 DPRINT("ObReference failed rc=%x\n",Status);
2874 ObDereferenceObject(Process);
2878 Status = MmMapViewOfSection(Section,
2889 ObDereferenceObject(Section);
2890 ObDereferenceObject(Process);
2896 MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
2897 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry,
2902 PFILE_OBJECT FileObject;
2903 PREACTOS_COMMON_FCB_HEADER Fcb;
2905 SWAPENTRY SavedSwapEntry;
2908 MArea = (PMEMORY_AREA)Context;
2910 Offset = ((ULONG)PAGE_ROUND_DOWN(Address) - (ULONG)MArea->BaseAddress) +
2911 MArea->Data.SectionData.ViewOffset;
2912 Entry = MmGetPageEntrySectionSegment(MArea->Data.SectionData.Segment,
2915 PageOp = MmCheckForPageOp(MArea, 0, NULL, MArea->Data.SectionData.Segment,
2920 KeWaitForSingleObject(&PageOp->CompletionEvent,
2925 MmReleasePageOp(PageOp);
2926 PageOp = MmCheckForPageOp(MArea, 0, NULL, MArea->Data.SectionData.Segment,
2930 assert(PageOp == NULL);
2933 * For a dirty, datafile, non-private page mark it as dirty in the
2936 if (MArea->Data.SectionData.Segment->Flags & MM_DATAFILE_SEGMENT)
2938 if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty)
2940 FileObject = MemoryArea->Data.SectionData.Section->FileObject;
2941 Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext;
2942 CcRosMarkDirtyCacheSegment(Fcb->Bcb, Offset);
2943 assert(SwapEntry == 0);
2949 MmFreeSwapPage(SwapEntry);
2951 else if (PhysAddr.QuadPart != 0)
2953 if (IS_SWAP_FROM_SSE(Entry) ||
2954 PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry)))
2957 * Just dereference private pages
2959 SavedSwapEntry = MmGetSavedSwapEntryPage(PhysAddr);
2960 if (SavedSwapEntry != 0)
2962 MmFreeSwapPage(SavedSwapEntry);
2963 MmSetSavedSwapEntryPage(PhysAddr, 0);
2965 MmDeleteRmap(PhysAddr, MArea->Process, Address);
2966 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
2970 MmUnsharePageEntrySectionSegment(MArea->Data.SectionData.Section,
2971 MArea->Data.SectionData.Segment,
2974 MmDeleteRmap(PhysAddr, MArea->Process, Address);
2975 MmReleasePageMemoryConsumer(MC_USER, PhysAddr);
2981 MmUnmapViewOfSection(PEPROCESS Process,
2985 PMEMORY_AREA MemoryArea;
2986 PMADDRESS_SPACE AddressSpace;
2987 PSECTION_OBJECT Section;
2988 PMM_SECTION_SEGMENT Segment;
2990 PLIST_ENTRY CurrentEntry;
2991 PMM_REGION CurrentRegion;
2993 AddressSpace = &Process->AddressSpace;
2995 DPRINT("Opening memory area Process %x BaseAddress %x\n",
2996 Process, BaseAddress);
2997 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
2999 if (MemoryArea == NULL)
3001 return(STATUS_UNSUCCESSFUL);
3004 MemoryArea->DeleteInProgress = TRUE;
3006 MmLockSection(MemoryArea->Data.SectionData.Section);
3007 MmLockSectionSegment(MemoryArea->Data.SectionData.Segment);
3008 Section = MemoryArea->Data.SectionData.Section;
3009 Segment = MemoryArea->Data.SectionData.Segment;
3010 KeAcquireSpinLock(&Section->ViewListLock, &oldIrql);
3011 RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry);
3012 KeReleaseSpinLock(&Section->ViewListLock, oldIrql);
3014 CurrentEntry = MemoryArea->Data.SectionData.RegionListHead.Flink;
3015 while (CurrentEntry != &MemoryArea->Data.SectionData.RegionListHead)
3018 CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry);
3019 CurrentEntry = CurrentEntry->Flink;
3020 ExFreePool(CurrentRegion);
3023 if (MemoryArea->Data.SectionData.Section->AllocationAttributes &
3026 Status = MmFreeMemoryArea(&Process->AddressSpace,
3034 Status = MmFreeMemoryArea(&Process->AddressSpace,
3040 MmUnlockSection(Section);
3041 MmUnlockSectionSegment(Segment);
3042 ObDereferenceObject(Section);
3043 return(STATUS_SUCCESS);
3046 /**********************************************************************
3048 * NtUnmapViewOfSection
3064 NtUnmapViewOfSection (HANDLE ProcessHandle,
3070 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3071 ProcessHandle, BaseAddress);
3073 DPRINT("Referencing process\n");
3074 Status = ObReferenceObjectByHandle(ProcessHandle,
3075 PROCESS_VM_OPERATION,
3080 if (!NT_SUCCESS(Status))
3082 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status);
3086 MmLockAddressSpace(&Process->AddressSpace);
3087 Status = MmUnmapViewOfSection(Process, BaseAddress);
3088 MmUnlockAddressSpace(&Process->AddressSpace);
3090 ObDereferenceObject(Process);
3097 NtQuerySection (IN HANDLE SectionHandle,
3098 IN CINT SectionInformationClass,
3099 OUT PVOID SectionInformation,
3101 OUT PULONG ResultLength)
3103 * FUNCTION: Queries the information of a section object.
3105 * SectionHandle = Handle to the section link object
3106 * SectionInformationClass = Index to a certain information structure
3107 * SectionInformation (OUT)= Caller supplies storage for resulting
3109 * Length = Size of the supplied storage
3110 * ResultLength = Data written
3115 PSECTION_OBJECT Section;
3118 Status = ObReferenceObjectByHandle(SectionHandle,
3120 MmSectionObjectType,
3124 if (!(NT_SUCCESS(Status)))
3129 switch (SectionInformationClass)
3131 case SectionBasicInformation:
3133 PSECTION_BASIC_INFORMATION Sbi;
3135 if (Length != sizeof(SECTION_BASIC_INFORMATION))
3137 ObDereferenceObject(Section);
3138 return(STATUS_INFO_LENGTH_MISMATCH);
3141 Sbi = (PSECTION_BASIC_INFORMATION)SectionInformation;
3143 Sbi->BaseAddress = 0;
3144 Sbi->Attributes = 0;
3145 Sbi->Size.QuadPart = 0;
3147 *ResultLength = sizeof(SECTION_BASIC_INFORMATION);
3148 Status = STATUS_SUCCESS;
3152 case SectionImageInformation:
3154 PSECTION_IMAGE_INFORMATION Sii;
3156 if (Length != sizeof(SECTION_IMAGE_INFORMATION))
3158 ObDereferenceObject(Section);
3159 return(STATUS_INFO_LENGTH_MISMATCH);
3161 Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation;
3162 Sii->EntryPoint = Section->EntryPoint;
3164 Sii->StackReserve = Section->StackReserve;
3165 Sii->StackCommit = Section->StackCommit;
3166 Sii->Subsystem = Section->Subsystem;
3167 Sii->MinorSubsystemVersion = Section->MinorSubsystemVersion;
3168 Sii->MajorSubsystemVersion = Section->MajorSubsystemVersion;
3170 Sii->Characteristics = Section->ImageCharacteristics;
3171 Sii->ImageNumber = Section->Machine;
3172 Sii->Executable = Section->Executable;
3174 Sii->Unknown4[0] = 0;
3175 Sii->Unknown4[1] = 0;
3176 Sii->Unknown4[2] = 0;
3178 *ResultLength = sizeof(SECTION_IMAGE_INFORMATION);
3179 Status = STATUS_SUCCESS;
3185 Status = STATUS_INVALID_INFO_CLASS;
3187 ObDereferenceObject(Section);
3193 NtExtendSection(IN HANDLE SectionHandle,
3194 IN ULONG NewMaximumSize)
3200 /**********************************************************************
3202 * MmAllocateSection@4
3212 * Code taken from ntoskrnl/mm/special.c.
3218 MmAllocateSection (IN ULONG Length)
3224 PMADDRESS_SPACE AddressSpace;
3226 DPRINT("MmAllocateSection(Length %x)\n",Length);
3228 AddressSpace = MmGetKernelAddressSpace();
3230 MmLockAddressSpace(AddressSpace);
3231 Status = MmCreateMemoryArea (NULL,
3239 if (!NT_SUCCESS(Status))
3241 MmUnlockAddressSpace(AddressSpace);
3244 MmUnlockAddressSpace(AddressSpace);
3245 DPRINT("Result %p\n",Result);
3246 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
3248 PHYSICAL_ADDRESS Page;
3250 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page);
3251 if (!NT_SUCCESS(Status))
3253 DbgPrint("Unable to allocate page\n");
3256 Status = MmCreateVirtualMapping (NULL,
3257 (Result + (i * PAGE_SIZE)),
3261 if (!NT_SUCCESS(Status))
3263 DbgPrint("Unable to create virtual mapping\n");
3267 return ((PVOID)Result);
3271 /**********************************************************************
3273 * MmMapViewOfSection
3276 * Maps a view of a section into the virtual address space of a
3281 * Pointer to the section object.
3284 * Pointer to the process.
3287 * Desired base address (or NULL) on entry;
3288 * Actual base address of the view on exit.
3291 * Number of high order address bits that must be zero.
3294 * Size in bytes of the initially committed section of
3298 * Offset in bytes from the beginning of the section
3299 * to the beginning of the view.
3302 * Desired length of map (or zero to map all) on entry
3303 * Actual length mapped on exit.
3305 * InheritDisposition
3306 * Specified how the view is to be shared with
3310 * Type of allocation for the pages.
3313 * Protection for the committed region of the view.
3319 MmMapViewOfSection(IN PVOID SectionObject,
3320 IN PEPROCESS Process,
3321 IN OUT PVOID *BaseAddress,
3323 IN ULONG CommitSize,
3324 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
3325 IN OUT PULONG ViewSize,
3326 IN SECTION_INHERIT InheritDisposition,
3327 IN ULONG AllocationType,
3330 PSECTION_OBJECT Section;
3331 PMADDRESS_SPACE AddressSpace;
3333 NTSTATUS Status = STATUS_SUCCESS;
3335 Section = (PSECTION_OBJECT)SectionObject;
3336 AddressSpace = &Process->AddressSpace;
3338 MmLockAddressSpace(AddressSpace);
3339 MmLockSection(SectionObject);
3341 if (Section->AllocationAttributes & SEC_IMAGE)
3347 ImageBase = *BaseAddress;
3348 if (ImageBase == NULL)
3350 ImageBase = Section->ImageBase;
3354 for (i = 0; i < Section->NrSegments; i++)
3356 if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3359 MaxExtent = (ULONG)(Section->Segments[i].VirtualAddress +
3360 Section->Segments[i].Length);
3361 ImageSize = max(ImageSize, MaxExtent);
3365 /* Check there is enough space to map the section at that point. */
3366 if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase,
3367 PAGE_ROUND_UP(ImageSize)) != NULL)
3369 /* Fail if the user requested a fixed base address. */
3370 if ((*BaseAddress) != NULL)
3372 MmUnlockSection(Section);
3373 MmUnlockAddressSpace(AddressSpace);
3374 return(STATUS_UNSUCCESSFUL);
3376 /* Otherwise find a gap to map the image. */
3377 ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize));
3378 if (ImageBase == NULL)
3380 MmUnlockSection(Section);
3381 MmUnlockAddressSpace(AddressSpace);
3382 return(STATUS_UNSUCCESSFUL);
3386 for (i = 0; i < Section->NrSegments; i++)
3390 if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD))
3392 SBaseAddress = (PVOID)
3393 (ImageBase + (ULONG_PTR)Section->Segments[i].VirtualAddress);
3395 MmLockSectionSegment(&Section->Segments[i]);
3396 Status = MmMapViewOfSegment(Process,
3397 &Process->AddressSpace,
3399 &Section->Segments[i],
3401 Section->Segments[i].Length,
3402 Section->Segments[i].Protection,
3403 Section->Segments[i].FileOffset);
3404 MmUnlockSectionSegment(&Section->Segments[i]);
3405 if (!NT_SUCCESS(Status))
3407 MmUnlockSection(Section);
3408 MmUnlockAddressSpace(AddressSpace);
3413 *BaseAddress = ImageBase;
3417 if (SectionOffset == NULL)
3423 ViewOffset = SectionOffset->u.LowPart;
3426 if ((ViewOffset % PAGE_SIZE) != 0)
3428 MmUnlockSection(Section);
3429 MmUnlockAddressSpace(AddressSpace);
3430 return(STATUS_MAPPED_ALIGNMENT);
3433 if ((*ViewSize) == 0)
3435 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3437 else if (((*ViewSize)+ViewOffset) > Section->MaximumSize.u.LowPart)
3439 (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset;
3442 MmLockSectionSegment(Section->Segments);
3443 Status = MmMapViewOfSegment(Process,
3444 &Process->AddressSpace,
3451 MmUnlockSectionSegment(Section->Segments);
3452 if (!NT_SUCCESS(Status))
3454 MmUnlockSection(Section);
3455 MmUnlockAddressSpace(AddressSpace);
3460 MmUnlockSection(Section);
3461 MmUnlockAddressSpace(AddressSpace);
3463 return(STATUS_SUCCESS);
3467 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3468 IN PLARGE_INTEGER NewFileSize)
3476 MmDisableModifiedWriteOfSection (DWORD Unknown0)
3483 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
3484 IN MMFLUSH_TYPE FlushType)
3491 MmForceSectionClosed (DWORD Unknown0,
3500 MmMapViewInSystemSpace (IN PVOID Section,
3501 OUT PVOID * MappedBase,
3505 return (STATUS_NOT_IMPLEMENTED);
3509 MmUnmapViewInSystemSpace (DWORD Unknown0)
3512 return (STATUS_NOT_IMPLEMENTED);
3517 MmSetBankedSection (DWORD Unknown0,
3525 return (STATUS_NOT_IMPLEMENTED);
3529 /**********************************************************************
3534 * Creates a section object.
3537 * SectionObjiect (OUT)
3538 * Caller supplied storage for the resulting pointer
3539 * to a SECTION_BOJECT instance;
3542 * Specifies the desired access to the section can be a
3544 * STANDARD_RIGHTS_REQUIRED |
3546 * SECTION_MAP_WRITE |
3547 * SECTION_MAP_READ |
3548 * SECTION_MAP_EXECUTE
3550 * ObjectAttributes [OPTIONAL]
3551 * Initialized attributes for the object can be used
3552 * to create a named section;
3555 * Maximizes the size of the memory section. Must be
3556 * non-NULL for a page-file backed section.
3557 * If value specified for a mapped file and the file is
3558 * not large enough, file will be extended.
3560 * SectionPageProtection
3561 * Can be a combination of:
3567 * AllocationAttributes
3568 * Can be a combination of:
3573 * Handle to a file to create a section mapped to a file
3574 * instead of a memory backed section;
3583 MmCreateSection (OUT PSECTION_OBJECT * SectionObject,
3584 IN ACCESS_MASK DesiredAccess,
3585 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
3586 IN PLARGE_INTEGER MaximumSize,
3587 IN ULONG SectionPageProtection,
3588 IN ULONG AllocationAttributes,
3589 IN HANDLE FileHandle OPTIONAL,
3590 IN PFILE_OBJECT File OPTIONAL)
3592 return (STATUS_NOT_IMPLEMENTED);