X-Git-Url: http://git.jankratochvil.net/?a=blobdiff_plain;f=ntoskrnl%2Fmm%2Fsection.c;h=a62e54cd39e86cee1049eab52404322af11b3e90;hb=HEAD;hp=d4b5f53d39df6a3637f37be7a0c023f01954a004;hpb=1334f77b1ecef00ac31076ce6bf22bdfeb82d347;p=reactos.git diff --git a/ntoskrnl/mm/section.c b/ntoskrnl/mm/section.c index d4b5f53..a62e54c 100644 --- a/ntoskrnl/mm/section.c +++ b/ntoskrnl/mm/section.c @@ -29,7 +29,8 @@ /* INCLUDES *****************************************************************/ #include -#include +#define NTOS_MODE_KERNEL +#include #include #include #include @@ -47,7 +48,7 @@ typedef struct { PSECTION_OBJECT Section; PMM_SECTION_SEGMENT Segment; - LARGE_INTEGER Offset; + ULONG Offset; BOOLEAN WasDirty; BOOLEAN Private; } MM_SECTION_PAGEOUT_CONTEXT; @@ -79,90 +80,72 @@ VOID MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment) { ULONG i; - - for (i = 0; i < NR_SECTION_PAGE_TABLES; i++) + if (Segment->Length > NR_SECTION_PAGE_TABLES * PAGE_SIZE) { - if (Segment->PageDirectory.PageTables[i] != NULL) - { - ExFreePool(Segment->PageDirectory.PageTables[i]); - } + for (i = 0; i < NR_SECTION_PAGE_TABLES; i++) + { + if (Segment->PageDirectory.PageTables[i] != NULL) + { + ExFreePool(Segment->PageDirectory.PageTables[i]); + } + } } } VOID MmFreeSectionSegments(PFILE_OBJECT FileObject) { - if (FileObject->SectionObjectPointers->ImageSectionObject != NULL) + if (FileObject->SectionObjectPointer->ImageSectionObject != NULL) { PMM_IMAGE_SECTION_OBJECT ImageSectionObject; - + PMM_SECTION_SEGMENT SectionSegments; + ULONG NrSegments; ULONG i; - ImageSectionObject = - (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointers-> - ImageSectionObject; - - for (i = 0; i < ImageSectionObject->NrSegments; i++) + ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT)FileObject->SectionObjectPointer->ImageSectionObject; + NrSegments = ImageSectionObject->NrSegments; + SectionSegments = ImageSectionObject->Segments; + for (i = 0; i < NrSegments; i++) { - if (ImageSectionObject->Segments[i].ReferenceCount != 0) + if (SectionSegments[i].ReferenceCount != 0) { DPRINT1("Image segment %d still referenced (was %d)\n", i, - ImageSectionObject->Segments[i].ReferenceCount); - KeBugCheck(0); + SectionSegments[i].ReferenceCount); + KEBUGCHECK(0); } - MmFreePageTablesSectionSegment(&ImageSectionObject->Segments[i]); + MmFreePageTablesSectionSegment(&SectionSegments[i]); } ExFreePool(ImageSectionObject); - FileObject->SectionObjectPointers->ImageSectionObject = NULL; + FileObject->SectionObjectPointer->ImageSectionObject = NULL; } - if (FileObject->SectionObjectPointers->DataSectionObject != NULL) + if (FileObject->SectionObjectPointer->DataSectionObject != NULL) { PMM_SECTION_SEGMENT Segment; - Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers-> + Segment = (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer-> DataSectionObject; if (Segment->ReferenceCount != 0) { DPRINT1("Data segment still referenced\n"); - KeBugCheck(0); + KEBUGCHECK(0); } MmFreePageTablesSectionSegment(Segment); ExFreePool(Segment); - FileObject->SectionObjectPointers->DataSectionObject = NULL; + FileObject->SectionObjectPointer->DataSectionObject = NULL; } } VOID -MmLockSection(PSECTION_OBJECT Section) -{ - KeWaitForSingleObject(&Section->Lock, - UserRequest, - KernelMode, - FALSE, - NULL); -} - -VOID -MmUnlockSection(PSECTION_OBJECT Section) -{ - KeReleaseMutex(&Section->Lock, FALSE); -} - -VOID MmLockSectionSegment(PMM_SECTION_SEGMENT Segment) { - KeWaitForSingleObject(&Segment->Lock, - UserRequest, - KernelMode, - FALSE, - NULL); + ExAcquireFastMutex(&Segment->Lock); } VOID MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment) { - KeReleaseMutex(&Segment->Lock, FALSE); + ExReleaseFastMutex(&Segment->Lock); } VOID @@ -173,17 +156,28 @@ MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, PSECTION_PAGE_TABLE Table; ULONG DirectoryOffset; ULONG TableOffset; - - DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset); - Table = Segment->PageDirectory.PageTables[DirectoryOffset]; - if (Table == NULL) + + if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE) { - Table = - Segment->PageDirectory.PageTables[DirectoryOffset] = - ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE), - TAG_SECTION_PAGE_TABLE); - memset(Table, 0, sizeof(SECTION_PAGE_TABLE)); - DPRINT("Table %x\n", Table); + Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory; + } + else + { + DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset); + Table = Segment->PageDirectory.PageTables[DirectoryOffset]; + if (Table == NULL) + { + Table = + Segment->PageDirectory.PageTables[DirectoryOffset] = + ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE), + TAG_SECTION_PAGE_TABLE); + if (Table == NULL) + { + KEBUGCHECK(0); + } + memset(Table, 0, sizeof(SECTION_PAGE_TABLE)); + DPRINT("Table %x\n", Table); + } } TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset); Table->Entry[TableOffset] = Entry; @@ -201,12 +195,19 @@ MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset); - DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset); - Table = Segment->PageDirectory.PageTables[DirectoryOffset]; - DPRINT("Table %x\n", Table); - if (Table == NULL) + if (Segment->Length <= NR_SECTION_PAGE_TABLES * PAGE_SIZE) { - return(0); + Table = (PSECTION_PAGE_TABLE)&Segment->PageDirectory; + } + else + { + DirectoryOffset = PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset); + Table = Segment->PageDirectory.PageTables[DirectoryOffset]; + DPRINT("Table %x\n", Table); + if (Table == NULL) + { + return(0); + } } TableOffset = PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset); Entry = Table->Entry[TableOffset]; @@ -223,16 +224,16 @@ MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, if (Entry == 0) { DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n"); - KeBugCheck(0); + KEBUGCHECK(0); } if (SHARE_COUNT_FROM_SSE(Entry) == MAX_SHARE_COUNT) { DPRINT1("Maximum share count reached\n"); - KeBugCheck(0); + KEBUGCHECK(0); } if (IS_SWAP_FROM_SSE(Entry)) { - KeBugCheck(0); + KEBUGCHECK(0); } Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) + 1); MmSetPageEntrySectionSegment(Segment, Offset, Entry); @@ -241,7 +242,7 @@ MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, BOOLEAN MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section, PMM_SECTION_SEGMENT Segment, - ULONG Offset, + ULONG Offset, BOOLEAN Dirty) { ULONG Entry; @@ -250,16 +251,16 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section, if (Entry == 0) { DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n"); - KeBugCheck(0); + KEBUGCHECK(0); } if (SHARE_COUNT_FROM_SSE(Entry) == 0) { DPRINT1("Zero share count for unshare\n"); - KeBugCheck(0); + KEBUGCHECK(0); } if (IS_SWAP_FROM_SSE(Entry)) { - KeBugCheck(0); + KEBUGCHECK(0); } Entry = MAKE_SSE(PAGE_FROM_SSE(Entry), SHARE_COUNT_FROM_SSE(Entry) - 1); /* @@ -269,46 +270,96 @@ MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section, if (SHARE_COUNT_FROM_SSE(Entry) == 0) { PFILE_OBJECT FileObject; - PREACTOS_COMMON_FCB_HEADER Fcb; + PBCB Bcb; SWAPENTRY SavedSwapEntry; PHYSICAL_ADDRESS Page; - - MmSetPageEntrySectionSegment(Segment, Offset, 0); + BOOLEAN IsImageSection; + ULONG FileOffset; + + FileOffset = Offset + Segment->FileOffset; + + IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; + + Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry); FileObject = Section->FileObject; if (FileObject != NULL) { - Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext; - + if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && - (Offset % PAGE_SIZE) == 0) + (FileOffset % PAGE_SIZE) == 0 && + (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection)) { NTSTATUS Status; - Status = CcRosUnmapCacheSegment(Fcb->Bcb, Offset, Dirty); + Bcb = FileObject->SectionObjectPointer->SharedCacheMap; + Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status); + KEBUGCHECK(0); } } } - Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry); SavedSwapEntry = MmGetSavedSwapEntryPage(Page); - if (SavedSwapEntry != 0) + if (SavedSwapEntry == 0) + { + if (Segment->Flags & MM_PAGEFILE_SEGMENT) + { + /* + * FIXME: + * Try to page out this page and set the swap entry + * within the section segment. There exist no rmap entry + * for this page. The pager thread can't page out a + * page without a rmap entry. + */ + MmSetPageEntrySectionSegment(Segment, Offset, Entry); + MmReferencePage(Page); + } + else + { + MmSetPageEntrySectionSegment(Segment, Offset, 0); + } + } + else { - MmFreeSwapPage(SavedSwapEntry); MmSetSavedSwapEntryPage(Page, 0); + if (Segment->Flags & MM_PAGEFILE_SEGMENT) + { + MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry)); + } + else + { + MmSetPageEntrySectionSegment(Segment, Offset, 0); + MmFreeSwapPage(SavedSwapEntry); + } } } else { MmSetPageEntrySectionSegment(Segment, Offset, Entry); } - return(SHARE_COUNT_FROM_SSE(Entry) > 1); + return(SHARE_COUNT_FROM_SSE(Entry) > 0); +} + +BOOL MiIsPageFromCache(PMEMORY_AREA MemoryArea, + ULONG SegOffset) +{ + PBCB Bcb; + PCACHE_SEGMENT CacheSeg; + + Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap; + CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset); + if (CacheSeg) + { + CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE); + return TRUE; + } + return FALSE; } NTSTATUS MiReadPage(PMEMORY_AREA MemoryArea, - PLARGE_INTEGER Offset, + ULONG SegOffset, PHYSICAL_ADDRESS* Page) /* * FUNCTION: Read a page for a section backed memory area. @@ -318,28 +369,37 @@ MiReadPage(PMEMORY_AREA MemoryArea, * Page - Variable that receives a page contains the read data. */ { - IO_STATUS_BLOCK IoStatus; + ULONG BaseOffset; + ULONG FileOffset; + PVOID BaseAddress; + BOOLEAN UptoDate; + PCACHE_SEGMENT CacheSeg; PFILE_OBJECT FileObject; - PMDL Mdl; NTSTATUS Status; - PREACTOS_COMMON_FCB_HEADER Fcb; - KEVENT Event; - + ULONG RawLength; + PBCB Bcb; + BOOLEAN IsImageSection; + ULONG Length; + FileObject = MemoryArea->Data.SectionData.Section->FileObject; - Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext; + Bcb = FileObject->SectionObjectPointer->SharedCacheMap; + RawLength = MemoryArea->Data.SectionData.Segment->RawLength; + FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->FileOffset; + IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; + assert(Bcb); + + DPRINT("%S %x\n", FileObject->FileName.Buffer, FileOffset); + /* * If the file system is letting us go directly to the cache and the * memory area was mapped at an offset in the file which is page aligned * then get the related cache segment. */ if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && - (Offset->QuadPart % PAGE_SIZE) == 0) + (FileOffset % PAGE_SIZE) == 0 && + (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection)) { - ULONG BaseOffset; - PVOID BaseAddress; - BOOLEAN UptoDate; - PCACHE_SEGMENT CacheSeg; PHYSICAL_ADDRESS Addr; /* @@ -347,12 +407,12 @@ MiReadPage(PMEMORY_AREA MemoryArea, * filesystems do because it is safe for us to use an offset with a * alignment less than the file system block size. */ - Status = CcRosGetCacheSegment(Fcb->Bcb, - (ULONG)Offset->QuadPart, - &BaseOffset, - &BaseAddress, - &UptoDate, - &CacheSeg); + Status = CcRosGetCacheSegment(Bcb, + FileOffset, + &BaseOffset, + &BaseAddress, + &UptoDate, + &CacheSeg); if (!NT_SUCCESS(Status)) { return(Status); @@ -366,6 +426,7 @@ MiReadPage(PMEMORY_AREA MemoryArea, Status = ReadCacheSegment(CacheSeg); if (!NT_SUCCESS(Status)) { + CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE); return Status; } } @@ -373,15 +434,16 @@ MiReadPage(PMEMORY_AREA MemoryArea, * Retrieve the page from the cache segment that we actually want. */ Addr = MmGetPhysicalAddress(BaseAddress + - Offset->QuadPart - BaseOffset); + FileOffset - BaseOffset); (*Page) = Addr; MmReferencePage((*Page)); - CcRosReleaseCacheSegment(Fcb->Bcb, CacheSeg, TRUE, FALSE, TRUE); - return(STATUS_SUCCESS); + CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, TRUE); } else { + PVOID PageAddr; + ULONG CacheSegOffset; /* * Allocate a page, this is rather complicated by the possibility * we might have to move other things out of memory @@ -391,29 +453,82 @@ MiReadPage(PMEMORY_AREA MemoryArea, { return(Status); } - - /* - * Create an mdl to hold the page we are going to read data into. - */ - Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE); - MmBuildMdlFromPages(Mdl, &Page->u.LowPart); - /* - * Call the FSD to read the page - */ - - KeInitializeEvent(&Event, NotificationEvent, FALSE); - Status = IoPageRead(FileObject, - Mdl, - Offset, - &Event, - &IoStatus); - if (Status == STATUS_PENDING) + Status = CcRosGetCacheSegment(Bcb, + FileOffset, + &BaseOffset, + &BaseAddress, + &UptoDate, + &CacheSeg); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + if (!UptoDate) + { + /* + * If the cache segment isn't up to date then call the file + * system to read in the data. + */ + Status = ReadCacheSegment(CacheSeg); + if (!NT_SUCCESS(Status)) + { + CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE); + return Status; + } + } + PageAddr = ExAllocatePageWithPhysPage(*Page); + CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset; + Length = RawLength - SegOffset; + if (Length <= CacheSegOffset && Length <= PAGE_SIZE) { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - return(IoStatus.Status); + memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, Length); } - return(Status); + else if (CacheSegOffset >= PAGE_SIZE) + { + memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, PAGE_SIZE); + } + else + { + memcpy(PageAddr, BaseAddress + FileOffset - BaseOffset, CacheSegOffset); + CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE); + Status = CcRosGetCacheSegment(Bcb, + FileOffset + CacheSegOffset, + &BaseOffset, + &BaseAddress, + &UptoDate, + &CacheSeg); + if (!NT_SUCCESS(Status)) + { + ExUnmapPage(PageAddr); + return(Status); + } + if (!UptoDate) + { + /* + * If the cache segment isn't up to date then call the file + * system to read in the data. + */ + Status = ReadCacheSegment(CacheSeg); + if (!NT_SUCCESS(Status)) + { + CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE); + ExUnmapPage(PageAddr); + return Status; + } + } + if (Length < PAGE_SIZE) + { + memcpy(PageAddr + CacheSegOffset, BaseAddress, Length - CacheSegOffset); + } + else + { + memcpy(PageAddr + CacheSegOffset, BaseAddress, PAGE_SIZE - CacheSegOffset); + } + } + CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE); + ExUnmapPage(PageAddr); } + return(STATUS_SUCCESS); } NTSTATUS @@ -422,7 +537,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, PVOID Address, BOOLEAN Locked) { - LARGE_INTEGER Offset; + ULONG Offset; LARGE_INTEGER Page; NTSTATUS Status; ULONG PAddress; @@ -433,34 +548,33 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, ULONG Attributes; PMM_PAGEOP PageOp; PMM_REGION Region; + LARGE_INTEGER Timeout; /* * There is a window between taking the page fault and locking the * address space when another thread could load the page so we check * that. */ - if (MmIsPagePresent(NULL, Address)) + if (MmIsPagePresent(AddressSpace->Process, Address)) { if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace->Process, Address)); } return(STATUS_SUCCESS); } PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address)); - Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) + - MemoryArea->Data.SectionData.ViewOffset; + Offset = PAddress - (ULONG)MemoryArea->BaseAddress; - /* - * Lock the segment - */ Segment = MemoryArea->Data.SectionData.Segment; Section = MemoryArea->Data.SectionData.Section; Region = MmFindRegion(MemoryArea->BaseAddress, &MemoryArea->Data.SectionData.RegionListHead, Address, NULL); - MmLockSection(Section); + /* + * Lock the segment + */ MmLockSectionSegment(Segment); /* @@ -470,7 +584,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, (Region->Protect == PAGE_READWRITE || Region->Protect == PAGE_EXECUTE_READWRITE)) { - Attributes = PAGE_READONLY; + Attributes = Region->Protect == PAGE_READWRITE ? PAGE_READONLY : PAGE_EXECUTE_READ; } else { @@ -480,12 +594,11 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, /* * Get or create a page operation descriptor */ - PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart, - MM_PAGEOP_PAGEIN); + PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_PAGEIN); if (PageOp == NULL) { DPRINT1("MmGetPageOp failed\n"); - KeBugCheck(0); + KEBUGCHECK(0); } /* @@ -495,86 +608,100 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, if (PageOp->Thread != PsGetCurrentThread()) { MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); + Timeout.QuadPart = -100000000LL; // 10 sec Status = KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, - NULL); + &Timeout); + /* * Check for various strange conditions */ if (Status != STATUS_SUCCESS) { - DPRINT1("Failed to wait for page op\n"); - KeBugCheck(0); + DPRINT1("Failed to wait for page op, status = %x\n", Status); + KEBUGCHECK(0); } if (PageOp->Status == STATUS_PENDING) { DPRINT1("Woke for page op before completion\n"); - KeBugCheck(0); + KEBUGCHECK(0); } + MmLockAddressSpace(AddressSpace); /* * If this wasn't a pagein then restart the operation */ if (PageOp->OpType != MM_PAGEOP_PAGEIN) { - MmLockAddressSpace(AddressSpace); + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); DPRINT("Address 0x%.8X\n", Address); return(STATUS_MM_RESTART_OPERATION); } + /* * If the thread handling this fault has failed then we don't retry */ if (!NT_SUCCESS(PageOp->Status)) { - MmLockAddressSpace(AddressSpace); + Status = PageOp->Status; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); DPRINT("Address 0x%.8X\n", Address); - return(PageOp->Status); + return(Status); } - MmLockAddressSpace(AddressSpace); - MmLockSection(Section); MmLockSectionSegment(Segment); /* * If the completed fault was for another address space then set the * page in this one. */ - if (!MmIsPagePresent(NULL, Address)) + if (!MmIsPagePresent(AddressSpace->Process, Address)) { - Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart); + Entry = MmGetPageEntrySectionSegment(Segment, Offset); if (Entry == 0) { - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); + MmUnlockSectionSegment(Segment); + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); return(STATUS_MM_RESTART_OPERATION); } Page = (LARGE_INTEGER)(LONGLONG)(PAGE_FROM_SSE(Entry)); MmReferencePage(Page); - MmSharePageEntrySectionSegment(Segment, Offset.u.LowPart); + MmSharePageEntrySectionSegment(Segment, Offset); - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Status = MmCreateVirtualMapping(MemoryArea->Process, Address, Attributes, Page, FALSE); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(MemoryArea->Process, + Address, + Attributes, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } + if (!NT_SUCCESS(Status)) { DbgPrint("Unable to create virtual mapping\n"); - KeBugCheck(0); + KEBUGCHECK(0); } - MmInsertRmap(Page, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); + MmInsertRmap(Page, MemoryArea->Process, (PVOID)PAddress); } if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(Page); } MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); + PageOp->Status = STATUS_SUCCESS; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); @@ -583,20 +710,28 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, /* * Must be private page we have swapped out. */ - if (MmIsPageSwapEntry(NULL, (PVOID)PAddress)) + if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)PAddress)) { SWAPENTRY SwapEntry; PMDL Mdl; + /* + * Sanity check + */ + if (Segment->Flags & MM_PAGEFILE_SEGMENT) + { + DPRINT1("Found a swaped out private page in a pagefile section.\n"); + KEBUGCHECK(0); + } + MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); - - MmDeletePageFileMapping(NULL, (PVOID)PAddress, &SwapEntry); + MmDeletePageFileMapping(AddressSpace->Process, (PVOID)PAddress, &SwapEntry); + MmUnlockAddressSpace(AddressSpace); Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + KEBUGCHECK(0); } Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE); @@ -604,18 +739,19 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, Status = MmReadFromSwapPage(SwapEntry, Mdl); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status); + KEBUGCHECK(0); } - - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + MmLockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, Region->Protect, Page, FALSE); - while (Status == STATUS_NO_MEMORY) + if (Status == STATUS_NO_MEMORY) { MmUnlockAddressSpace(AddressSpace); - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, Region->Protect, Page, @@ -624,8 +760,8 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, } if (!NT_SUCCESS(Status)) { - DPRINT1("MmCreateVirtualMapping failed, not out of memory\n"); - KeBugCheck(0); + DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); + KEBUGCHECK(0); return(Status); } @@ -637,8 +773,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, /* * Add the page to the process's working set */ - MmInsertRmap(Page, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); + MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress); /* * Finish the operation @@ -659,21 +794,39 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, */ if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) { + MmUnlockSectionSegment(Segment); /* * Just map the desired physical page */ - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Page.QuadPart = Offset + MemoryArea->Data.SectionData.ViewOffset; + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, Region->Protect, - Offset, + Page, FALSE); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Region->Protect, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } + if (!NT_SUCCESS(Status)) + { + DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); + KEBUGCHECK(0); + return(Status); + } /* * Don't add an rmap entry since the page mapped could be for * anything. */ if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(Page); } /* @@ -682,8 +835,6 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); } @@ -693,28 +844,44 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, */ if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) { + MmUnlockSectionSegment(Segment); Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page); if (!NT_SUCCESS(Status)) { - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); - MmUnlockAddressSpace(AddressSpace); - MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); - MmLockAddressSpace(AddressSpace); - MmLockSection(Section); - MmLockSectionSegment(Segment); + MmUnlockAddressSpace(AddressSpace); + Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); + MmLockAddressSpace(AddressSpace); } - - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + if (!NT_SUCCESS(Status)) + { + KEBUGCHECK(0); + } + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, Region->Protect, Page, FALSE); - MmInsertRmap(Page, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Region->Protect, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } + + if (!NT_SUCCESS(Status)) + { + DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); + KEBUGCHECK(0); + return(Status); + } + MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress); if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(Page); } /* @@ -723,8 +890,6 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); } @@ -732,7 +897,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, /* * Get the entry corresponding to the offset within the section */ - Entry = MmGetPageEntrySectionSegment(Segment, Offset.u.LowPart); + Entry = MmGetPageEntrySectionSegment(Segment, Offset); if (Entry == 0) { @@ -740,105 +905,100 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, * If the entry is zero (and it can't change because we have * locked the segment) then we need to load the page. */ - + /* * Release all our locks and read in the page from disk */ MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); - - if (Segment->Flags & MM_PAGEFILE_SEGMENT) + + if ((Segment->Flags & MM_PAGEFILE_SEGMENT) || + (Offset >= PAGE_ROUND_UP(Segment->RawLength) && Section->AllocationAttributes & SEC_IMAGE)) { - Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); + Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); + if (!NT_SUCCESS(Status)) + { + DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status); + } } else - { - Status = MiReadPage(MemoryArea, &Offset, &Page); + { + Status = MiReadPage(MemoryArea, Offset, &Page); + if (!NT_SUCCESS(Status)) + { + DPRINT1("MiReadPage failed (Status %x)\n", Status); + } } - if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) + if (!NT_SUCCESS(Status)) { /* * FIXME: What do we know in this case? */ - DPRINT1("IoPageRead failed (Status %x)\n", Status); - /* * Cleanup and release locks */ + MmLockAddressSpace(AddressSpace); PageOp->Status = Status; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - MmLockAddressSpace(AddressSpace); + DPRINT("Address 0x%.8X\n", Address); return(Status); } - /* - * Relock the address space, section and segment + * Relock the address space and segment */ MmLockAddressSpace(AddressSpace); - MmLockSection(Section); MmLockSectionSegment(Segment); /* * Check the entry. No one should change the status of a page * that has a pending page-in. */ - Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart); + Entry1 = MmGetPageEntrySectionSegment(Segment, Offset); if (Entry != Entry1) { DbgPrint("Someone changed ppte entry while we slept\n"); - KeBugCheck(0); + KEBUGCHECK(0); } /* * Mark the offset within the section as having valid, in-memory * data */ - Entry = Page.u.LowPart; - MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry); - MmSharePageEntrySectionSegment(Segment, Offset.QuadPart); - - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Entry = MAKE_SSE(Page.u.LowPart, 1); + MmSetPageEntrySectionSegment(Segment, Offset, Entry); + MmUnlockSectionSegment(Segment); + + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, Attributes, Page, FALSE); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Attributes, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } if (!NT_SUCCESS(Status)) - { - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); - MmUnlockAddressSpace(AddressSpace); - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), - Address, - Attributes, - Page, - TRUE); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(0); - } - MmLockAddressSpace(AddressSpace); - MmLockSection(Section); - MmLockSectionSegment(Segment); - } - MmInsertRmap(Page, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); - if (!NT_SUCCESS(Status)) - { - DbgPrint("Unable to create virtual mapping\n"); - KeBugCheck(0); - } + { + DbgPrint("Unable to create virtual mapping\n"); + KEBUGCHECK(0); + } + MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress); + if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(Page); } PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); - DPRINT("MmNotPresentFaultSectionView succeeded\n"); + DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); } else if (IS_SWAP_FROM_SSE(Entry)) @@ -852,13 +1012,13 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, * Release all our locks and read in the page from disk */ MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); + MmUnlockAddressSpace(AddressSpace); Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + KEBUGCHECK(0); } Mdl = MmCreateMdl(NULL, NULL, PAGE_SIZE); @@ -866,96 +1026,110 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, Status = MmReadFromSwapPage(SwapEntry, Mdl); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + KEBUGCHECK(0); } /* - * Relock the address space, section and segment + * Relock the address space and segment */ MmLockAddressSpace(AddressSpace); - MmLockSection(Section); MmLockSectionSegment(Segment); /* * Check the entry. No one should change the status of a page * that has a pending page-in. */ - Entry1 = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart); + Entry1 = MmGetPageEntrySectionSegment(Segment, Offset); if (Entry != Entry1) { DbgPrint("Someone changed ppte entry while we slept\n"); - KeBugCheck(0); + KEBUGCHECK(0); } /* * Mark the offset within the section as having valid, in-memory * data */ - Entry = Page.u.LowPart; - MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry); - MmSharePageEntrySectionSegment(Segment, Offset.QuadPart); + Entry = MAKE_SSE(Page.u.LowPart, 1); + MmSetPageEntrySectionSegment(Segment, Offset, Entry); + MmUnlockSectionSegment(Segment); /* * Save the swap entry. */ MmSetSavedSwapEntryPage(Page, SwapEntry); - - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, - Attributes, + Region->Protect, Page, FALSE); - MmInsertRmap(Page, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Region->Protect, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } if (!NT_SUCCESS(Status)) - { - DbgPrint("Unable to create virtual mapping\n"); - KeBugCheck(0); - } + { + DbgPrint("Unable to create virtual mapping\n"); + KEBUGCHECK(0); + } + MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress); if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(Page); } PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); - DPRINT("MmNotPresentFaultSectionView succeeded\n"); + DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); } else { - /* - * If the section offset is already in-memory and valid then just - * take another reference to the page - */ - - Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry); - MmReferencePage(Page); - MmSharePageEntrySectionSegment(Segment, Offset.QuadPart); + /* + * If the section offset is already in-memory and valid then just + * take another reference to the page + */ - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), - Address, - Attributes, - Page, - FALSE); - MmInsertRmap(Page, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); - if (!NT_SUCCESS(Status)) - { - DbgPrint("Unable to create virtual mapping\n"); - KeBugCheck(0); - } + Page = (LARGE_INTEGER)(LONGLONG)PAGE_FROM_SSE(Entry); + MmReferencePage(Page); + MmSharePageEntrySectionSegment(Segment, Offset); + MmUnlockSectionSegment(Segment); + + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Attributes, + Page, + FALSE); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Attributes, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } + if (!NT_SUCCESS(Status)) + { + DbgPrint("Unable to create virtual mapping\n"); + KEBUGCHECK(0); + } + MmInsertRmap(Page, AddressSpace->Process, (PVOID)PAddress); if (Locked) - { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); - } + { + MmLockPage(Page); + } PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); + DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); } } @@ -973,46 +1147,46 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, PVOID NewAddress; NTSTATUS Status; ULONG PAddress; - LARGE_INTEGER Offset; + ULONG Offset; PMM_PAGEOP PageOp; PMM_REGION Region; + LARGE_INTEGER Timeout; /* * Check if the page has been paged out or has already been set readwrite */ - if (!MmIsPagePresent(NULL, Address) || - MmGetPageProtect(NULL, Address) & PAGE_READWRITE) + if (!MmIsPagePresent(AddressSpace->Process, Address) || + MmGetPageProtect(AddressSpace->Process, Address) & PAGE_READWRITE) { - return(STATUS_SUCCESS); + DPRINT("Address 0x%.8X\n", Address); + return(STATUS_SUCCESS); } /* * Find the offset of the page */ PAddress = (ULONG)PAGE_ROUND_DOWN(((ULONG)Address)); - Offset.QuadPart = (PAddress - (ULONG)MemoryArea->BaseAddress) + - MemoryArea->Data.SectionData.ViewOffset; + Offset = PAddress - (ULONG)MemoryArea->BaseAddress; - /* - * Lock the segment - */ Segment = MemoryArea->Data.SectionData.Segment; Section = MemoryArea->Data.SectionData.Section; Region = MmFindRegion(MemoryArea->BaseAddress, &MemoryArea->Data.SectionData.RegionListHead, Address, NULL); - MmLockSection(Section); + /* + * Lock the segment + */ MmLockSectionSegment(Segment); /* * Sanity check. */ - if (MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) == 0) + if (MmGetPageEntrySectionSegment(Segment, Offset) == 0) { DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n", Address); } - + MmUnlockSectionSegment(Segment); /* * Check if we are doing COW */ @@ -1020,20 +1194,19 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, (Region->Protect == PAGE_READWRITE || Region->Protect == PAGE_EXECUTE_READWRITE))) { - MmUnlockSection(Section); - MmUnlockSectionSegment(Segment); + DPRINT("Address 0x%.8X\n", Address); return(STATUS_UNSUCCESSFUL); } /* * Get or create a pageop */ - PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset.u.LowPart, + PageOp = MmGetPageOp(MemoryArea, 0, 0, Segment, Offset, MM_PAGEOP_ACCESSFAULT); if (PageOp == NULL) { DPRINT1("MmGetPageOp failed\n"); - KeBugCheck(0); + KEBUGCHECK(0); } /* @@ -1041,46 +1214,49 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, */ if (PageOp->Thread != PsGetCurrentThread()) { - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); + Timeout.QuadPart = -100000000LL; // 10 sec Status = KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, - NULL); + &Timeout); /* * Check for various strange conditions */ - if (Status != STATUS_SUCCESS) + if (Status == STATUS_TIMEOUT) { - DPRINT1("Failed to wait for page op\n"); - KeBugCheck(0); + DPRINT1("Failed to wait for page op, status = %x\n", Status); + KEBUGCHECK(0); } if (PageOp->Status == STATUS_PENDING) { DPRINT1("Woke for page op before completion\n"); - KeBugCheck(0); + KEBUGCHECK(0); } /* * Restart the operation */ MmLockAddressSpace(AddressSpace); + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); + DPRINT("Address 0x%.8X\n", Address); return(STATUS_MM_RESTART_OPERATION); } /* * Release locks now we have the pageop */ - MmUnlockSectionSegment(Segment); - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); /* * Allocate a page */ Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &NewPage); + if (!NT_SUCCESS(Status)) + { + KEBUGCHECK(0); + } /* * Copy the old page @@ -1088,46 +1264,63 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, OldPage = MmGetPhysicalAddressForProcess(NULL, Address); NewAddress = ExAllocatePageWithPhysPage(NewPage); - memcpy(NewAddress, (PVOID)PAGE_ROUND_DOWN(Address), PAGE_SIZE); + memcpy(NewAddress, (PVOID)PAddress, PAGE_SIZE); ExUnmapPage(NewAddress); /* * Delete the old entry. */ - MmDeleteVirtualMapping(PsGetCurrentProcess(), Address, FALSE, NULL, NULL); + MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL); /* * Set the PTE to point to the new page */ MmLockAddressSpace(AddressSpace); - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Status = MmCreateVirtualMapping(AddressSpace->Process, Address, Region->Protect, NewPage, FALSE); - MmInsertRmap(NewPage, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(AddressSpace->Process, + Address, + Region->Protect, + NewPage, + TRUE); + MmLockAddressSpace(AddressSpace); + } + if (!NT_SUCCESS(Status)) + { + DPRINT("MmCreateVirtualMapping failed, not out of memory\n"); + KEBUGCHECK(0); + return(Status); + } + MmInsertRmap(NewPage, AddressSpace->Process, (PVOID)PAddress); if (!NT_SUCCESS(Status)) { DbgPrint("Unable to create virtual mapping\n"); - KeBugCheck(0); + KEBUGCHECK(0); } if (Locked) { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + MmLockPage(NewPage); } /* * Unshare the old page. */ - MmUnsharePageEntrySectionSegment(Section, Segment, Offset.QuadPart, FALSE); - MmDeleteRmap(OldPage, PsGetCurrentProcess(), - (PVOID)PAGE_ROUND_DOWN(Address)); + MmDeleteRmap(OldPage, AddressSpace->Process, (PVOID)PAddress); + MmLockSectionSegment(Segment); + MmUnsharePageEntrySectionSegment(Section, Segment, Offset, FALSE); + MmUnlockSectionSegment(Segment); MmReleasePageMemoryConsumer(MC_USER, OldPage); PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); + DPRINT("Address 0x%.8X\n", Address); return(STATUS_SUCCESS); } @@ -1136,14 +1329,14 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address) { MM_SECTION_PAGEOUT_CONTEXT* PageOutContext; BOOL WasDirty; - PHYSICAL_ADDRESS PhysicalAddress; + PHYSICAL_ADDRESS Page; PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context; MmDeleteVirtualMapping(Process, Address, FALSE, &WasDirty, - &PhysicalAddress); + &Page); if (WasDirty) { PageOutContext->WasDirty = TRUE; @@ -1152,10 +1345,11 @@ MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address) { MmUnsharePageEntrySectionSegment(PageOutContext->Section, PageOutContext->Segment, - PageOutContext->Offset.u.LowPart, + PageOutContext->Offset, PageOutContext->WasDirty); } - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + MmReleasePageMemoryConsumer(MC_USER, Page); + DPRINT("PhysicalAddress %I64x, Address %x\n", Page, Address); } NTSTATUS @@ -1164,30 +1358,36 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, PVOID Address, PMM_PAGEOP PageOp) { - LARGE_INTEGER Offset; - PSECTION_OBJECT Section; - PMM_SECTION_SEGMENT Segment; PHYSICAL_ADDRESS PhysicalAddress; MM_SECTION_PAGEOUT_CONTEXT Context; SWAPENTRY SwapEntry; PMDL Mdl; ULONG Entry; - BOOLEAN Private; + ULONG FileOffset; NTSTATUS Status; PFILE_OBJECT FileObject; - PREACTOS_COMMON_FCB_HEADER Fcb; + PBCB Bcb = NULL; BOOLEAN DirectMapped; + BOOLEAN IsImageSection; Address = (PVOID)PAGE_ROUND_DOWN(Address); - Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) + - MemoryArea->Data.SectionData.ViewOffset; + /* + * Get the segment and section. + */ + Context.Segment = MemoryArea->Data.SectionData.Segment; + Context.Section = MemoryArea->Data.SectionData.Section; - FileObject = MemoryArea->Data.SectionData.Section->FileObject; + Context.Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress); + FileOffset = Context.Offset + Context.Segment->FileOffset; + + IsImageSection = Context.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; + + FileObject = Context.Section->FileObject; DirectMapped = FALSE; if (FileObject != NULL) { - Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext; + Bcb = FileObject->SectionObjectPointer->SharedCacheMap; /* * If the file system is letting us go directly to the cache and the @@ -1195,38 +1395,35 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, * then note this is a direct mapped page. */ if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && - (Offset.QuadPart % PAGE_SIZE) == 0) + (FileOffset % PAGE_SIZE) == 0 && + (Context.Offset + PAGE_SIZE <= Context.Segment->RawLength || !IsImageSection)) { DirectMapped = TRUE; } } - /* - * Get the segment and section. - */ - Segment = MemoryArea->Data.SectionData.Segment; - Section = MemoryArea->Data.SectionData.Section; /* * This should never happen since mappings of physical memory are never * placed in the rmap lists. */ - if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) + if (Context.Section->AllocationAttributes & SEC_PHYSICALMEMORY) { DPRINT1("Trying to page out from physical memory section address 0x%X " - "process %d\n", Address, AddressSpace->Process->UniqueProcessId); - KeBugCheck(0); + "process %d\n", Address, + AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0); + KEBUGCHECK(0); } /* * Get the section segment entry and the physical address. */ - Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart); + Entry = MmGetPageEntrySectionSegment(Context.Segment, Context.Offset); if (!MmIsPagePresent(AddressSpace->Process, Address)) { DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n", - AddressSpace->Process->UniqueProcessId, Address); - KeBugCheck(0); + AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address); + KEBUGCHECK(0); } PhysicalAddress = MmGetPhysicalAddressForProcess(AddressSpace->Process, Address); @@ -1235,31 +1432,22 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, /* * Prepare the context structure for the rmap delete call. */ - Context.Section = Section; - Context.Segment = Segment; - Context.Offset = Offset; Context.WasDirty = FALSE; - if (Segment->Characteristics & IMAGE_SECTION_CHAR_BSS || + if (Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS || IS_SWAP_FROM_SSE(Entry) || (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart) { - Context.Private = Private = TRUE; + Context.Private = TRUE; } else { - Context.Private = Private = FALSE; + Context.Private = FALSE; } /* - * Take an additional reference to the page. - */ - MmReferencePage(PhysicalAddress); - - /* * Paging out data mapped read-only is easy. */ - if (MemoryArea->Attributes & PAGE_READONLY || - MemoryArea->Attributes & PAGE_EXECUTE_READ) + if (Context.Segment->Protection & (PAGE_READONLY|PAGE_EXECUTE_READ)) { /* * Read-only data should never be in the swapfile. @@ -1269,16 +1457,16 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, " "paddress 0x%.8X\n", SwapEntry, Address, PhysicalAddress); - KeBugCheck(0); + KEBUGCHECK(0); } /* * Read-only data should never be COWed */ - if (Private) + if (Context.Private) { DPRINT1("Had private copy of read-only page.\n"); - KeBugCheck(0); + KEBUGCHECK(0); } /* @@ -1288,18 +1476,10 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, MmPageOutDeleteMapping); if (Context.WasDirty) { - KeBugCheck(0); - } - /* - * If this page wasn't direct mapped then we have a private copy so - * release back to the system; otherwise the cache manager will have - * handled freeing the cache segment which we mapped from. - */ - if (!DirectMapped) - { - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + DPRINT1("Had a dirty page of a read-only page.\n"); + KEBUGCHECK(0); } - + PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); @@ -1309,39 +1489,61 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, /* * Otherwise we have read-write data. */ + + /* + * Take an additional reference to the page or the cache segment. + */ + if (DirectMapped && !Context.Private) + { + if(!MiIsPageFromCache(MemoryArea, Context.Offset)) + { + DPRINT1("Direct mapped non private page is not associated with the cache.\n") + KEBUGCHECK(0); + } + } + else + { + MmReferencePage(PhysicalAddress); + } + MmDeleteAllRmaps(PhysicalAddress, (PVOID)&Context, MmPageOutDeleteMapping); /* * If this wasn't a private page then we should have reduced the entry to * zero by deleting all the rmaps. */ - if (!Private && MmGetPageEntrySectionSegment(Segment, Offset.QuadPart) != 0) + if (!Context.Private && MmGetPageEntrySectionSegment(Context.Segment, Context.Offset) != 0) { - KeBugCheck(0); + if (!(Context.Segment->Flags & MM_PAGEFILE_SEGMENT)) + { + CHECKPOINT1; + KEBUGCHECK(0); + } } /* * If the page wasn't dirty then we can just free it as for a readonly page. * Since we unmapped all the mappings above we know it will not suddenly - * become dirty. + * become dirty. + * If the page is from a pagefile section and has no swap entry, + * we can't free the page at this point. */ - if (!Context.WasDirty) + SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress); + if (!Context.WasDirty && + !(SwapEntry == 0 && Context.Segment->Flags & MM_PAGEFILE_SEGMENT)) + { - if (!DirectMapped || Private) + if (Context.Private) { MmSetSavedSwapEntryPage(PhysicalAddress, 0); - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); - } - if (Private) - { - if (!(Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) && + if (!(Context.Segment->Characteristics & IMAGE_SECTION_CHAR_BSS) && SwapEntry == 0) { DPRINT1("Private page, non-dirty but not swapped out " "process %d address 0x%.8X\n", - AddressSpace->Process->UniqueProcessId, + AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address); - KeBugCheck(0); + KEBUGCHECK(0); } else { @@ -1350,10 +1552,23 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, SwapEntry); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + KEBUGCHECK(0); } } } + if (DirectMapped && !Context.Private) + { + Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status); + KEBUGCHECK(0); + } + } + else + { + MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + } PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); @@ -1365,10 +1580,15 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, * If this page was direct mapped from the cache then the cache manager * will already have taken care of writing it back. */ - if (DirectMapped && !Private) + if (DirectMapped && !Context.Private) { assert(SwapEntry == 0); - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status); + KEBUGCHECK(0); + } PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); @@ -1378,7 +1598,6 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, /* * If necessary, allocate an entry in the paging file for this page */ - SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress); if (SwapEntry == 0) { SwapEntry = MmAllocSwapPage(); @@ -1389,7 +1608,7 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, /* * For private pages restore the old mappings. */ - if (Private) + if (Context.Private) { Status = MmCreateVirtualMapping(MemoryArea->Process, Address, @@ -1417,14 +1636,13 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, MmInsertRmap(PhysicalAddress, MemoryArea->Process, Address); - MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, - PhysicalAddress.u.LowPart); - MmSharePageEntrySectionSegment(Segment, Offset.QuadPart); + Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1); + MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry); } - PageOp->Status = STATUS_UNSUCCESSFUL; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_UNSUCCESSFUL); + PageOp->Status = STATUS_UNSUCCESSFUL; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_PAGEFILE_QUOTA); } } @@ -1442,7 +1660,7 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, * As above: undo our actions. * FIXME: Also free the swap page. */ - if (Private) + if (Context.Private) { Status = MmCreateVirtualMapping(MemoryArea->Process, Address, @@ -1465,9 +1683,8 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, MmInsertRmap(PhysicalAddress, MemoryArea->Process, Address); - MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, - PhysicalAddress.u.LowPart); - MmSharePageEntrySectionSegment(Segment, Offset.QuadPart); + Entry = MAKE_SSE(PhysicalAddress.u.LowPart, 1); + MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry); } PageOp->Status = STATUS_UNSUCCESSFUL; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); @@ -1482,20 +1699,20 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, MmSetSavedSwapEntryPage(PhysicalAddress, 0); MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); - if (Private) + if (Context.Private) { Status = MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry); if (!NT_SUCCESS(Status)) { - KeBugCheck(0); + KEBUGCHECK(0); } } else { Entry = MAKE_SWAP_SSE(SwapEntry); - MmSetPageEntrySectionSegment(Segment, Offset.QuadPart, Entry); + MmSetPageEntrySectionSegment(Context.Segment, Context.Offset, Entry); } PageOp->Status = STATUS_SUCCESS; @@ -1510,7 +1727,7 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace, PVOID Address, PMM_PAGEOP PageOp) { - LARGE_INTEGER Offset; + ULONG Offset; PSECTION_OBJECT Section; PMM_SECTION_SEGMENT Segment; PHYSICAL_ADDRESS PhysicalAddress; @@ -1520,19 +1737,26 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace, BOOLEAN Private; NTSTATUS Status; PFILE_OBJECT FileObject; - PREACTOS_COMMON_FCB_HEADER Fcb = NULL; + PBCB Bcb = NULL; BOOLEAN DirectMapped; + BOOLEAN IsImageSection; Address = (PVOID)PAGE_ROUND_DOWN(Address); - Offset.QuadPart = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) + - MemoryArea->Data.SectionData.ViewOffset; + Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress); - FileObject = MemoryArea->Data.SectionData.Section->FileObject; + /* + * Get the segment and section. + */ + Segment = MemoryArea->Data.SectionData.Segment; + Section = MemoryArea->Data.SectionData.Section; + IsImageSection = Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE; + + FileObject = Section->FileObject; DirectMapped = FALSE; if (FileObject != NULL) { - Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext; + Bcb = FileObject->SectionObjectPointer->SharedCacheMap; /* * If the file system is letting us go directly to the cache and the @@ -1540,38 +1764,34 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace, * then note this is a direct mapped page. */ if (FileObject->Flags & FO_DIRECT_CACHE_PAGING_READ && - (Offset.QuadPart % PAGE_SIZE) == 0) + (Offset + MemoryArea->Data.SectionData.ViewOffset % PAGE_SIZE) == 0 && + (Offset + PAGE_SIZE <= Segment->RawLength || !IsImageSection)) { DirectMapped = TRUE; } } /* - * Get the segment and section. - */ - Segment = MemoryArea->Data.SectionData.Segment; - Section = MemoryArea->Data.SectionData.Section; - - /* * This should never happen since mappings of physical memory are never * placed in the rmap lists. */ if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) { DPRINT1("Trying to write back page from physical memory mapped at %X " - "process %d\n", Address, AddressSpace->Process->UniqueProcessId); - KeBugCheck(0); + "process %d\n", Address, + AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0); + KEBUGCHECK(0); } /* * Get the section segment entry and the physical address. */ - Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart); + Entry = MmGetPageEntrySectionSegment(Segment, Offset); if (!MmIsPagePresent(AddressSpace->Process, Address)) { DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n", - AddressSpace->Process->UniqueProcessId, Address); - KeBugCheck(0); + AddressSpace->Process ? AddressSpace->Process->UniqueProcessId : 0, Address); + KEBUGCHECK(0); } PhysicalAddress = MmGetPhysicalAddressForProcess(AddressSpace->Process, Address); @@ -1603,7 +1823,7 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace, if (DirectMapped && !Private) { assert(SwapEntry == 0); - CcRosMarkDirtyCacheSegment(Fcb->Bcb, Offset.u.LowPart); + CcRosMarkDirtyCacheSegment(Bcb, Offset + MemoryArea->Data.SectionData.ViewOffset); PageOp->Status = STATUS_SUCCESS; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); @@ -1613,7 +1833,6 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace, /* * If necessary, allocate an entry in the paging file for this page */ - SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress); if (SwapEntry == 0) { SwapEntry = MmAllocSwapPage(); @@ -1623,7 +1842,7 @@ MmWritePageSectionView(PMADDRESS_SPACE AddressSpace, PageOp->Status = STATUS_UNSUCCESSFUL; KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); MmReleasePageOp(PageOp); - return(STATUS_UNSUCCESSFUL); + return(STATUS_PAGEFILE_QUOTA); } } @@ -1680,7 +1899,7 @@ MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace, if (OldProtect != NewProtect) { - for (i = 0; i < (RegionSize / PAGE_SIZE); i++) + for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++) { PVOID Address = BaseAddress + (i * PAGE_SIZE); ULONG Protect = NewProtect; @@ -1691,14 +1910,12 @@ MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace, */ if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address)) { - LARGE_INTEGER Offset; + ULONG Offset; ULONG Entry; LARGE_INTEGER PhysicalAddress; - Offset.QuadPart = - (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) + - MemoryArea->Data.SectionData.ViewOffset; - Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart); + Offset = (ULONG)Address - (ULONG)MemoryArea->BaseAddress; + Entry = MmGetPageEntrySectionSegment(Segment, Offset); PhysicalAddress = MmGetPhysicalAddressForProcess(AddressSpace->Process, Address); @@ -1732,7 +1949,7 @@ MmProtectSectionView(PMADDRESS_SPACE AddressSpace, NTSTATUS Status; Length = - min(Length, MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress); + min(Length, (ULONG) (MemoryArea->BaseAddress + MemoryArea->Length - BaseAddress)); Region = MmFindRegion(MemoryArea->BaseAddress, &MemoryArea->Data.SectionData.RegionListHead, BaseAddress, NULL); @@ -1757,6 +1974,10 @@ MmQuerySectionView(PMEMORY_AREA MemoryArea, Region = MmFindRegion(MemoryArea->BaseAddress, &MemoryArea->Data.SectionData.RegionListHead, Address, &RegionBaseAddress); + if (Region == NULL) + { + return STATUS_UNSUCCESSFUL; + } Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address); Info->AllocationBase = MemoryArea->BaseAddress; Info->AllocationProtect = MemoryArea->Attributes; @@ -1784,22 +2005,60 @@ MmpDeleteSection(PVOID ObjectBody) if (Section->AllocationAttributes & SEC_IMAGE) { ULONG i; - - for (i = 0; i < Section->NrSegments; i++) + ULONG NrSegments; + PMM_SECTION_SEGMENT SectionSegments; + + SectionSegments = Section->ImageSection->Segments; + NrSegments = Section->ImageSection->NrSegments; + + for (i = 0; i < NrSegments; i++) { - InterlockedDecrement(&Section->Segments[i].ReferenceCount); + InterlockedDecrement((LONG *)&SectionSegments[i].ReferenceCount); } } else { - InterlockedDecrement(&Section->Segments->ReferenceCount); + if (Section->Segment->Flags & MM_PAGEFILE_SEGMENT) + { + ULONG Offset; + ULONG Length; + ULONG Entry; + PMM_SECTION_SEGMENT Segment; + + Segment = Section->Segment; + Length = PAGE_ROUND_UP(Segment->Length); + + for (Offset = 0; Offset < Length; Offset += PAGE_SIZE) + { + Entry = MmGetPageEntrySectionSegment(Segment, Offset); + if (Entry) + { + if (IS_SWAP_FROM_SSE(Entry)) + { + MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry)); + } + else + { + PHYSICAL_ADDRESS Page = (PHYSICAL_ADDRESS)(LONGLONG)PAGE_FROM_SSE(Entry); + MmReleasePageMemoryConsumer(MC_USER, Page); + } + } + } + MmFreePageTablesSectionSegment(Section->Segment); + ExFreePool(Section->Segment); + Section->Segment = NULL; + } + else + { + InterlockedDecrement((LONG *)&Section->Segment->ReferenceCount); + } } if (Section->FileObject != NULL) { CcRosDereferenceCache(Section->FileObject); ObDereferenceObject(Section->FileObject); Section->FileObject = NULL; - } + } } VOID STDCALL @@ -1808,7 +2067,6 @@ MmpCloseSection(PVOID ObjectBody, { DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n", ObjectBody, HandleCount, ObGetObjectPointerCount(ObjectBody)); - } NTSTATUS STDCALL @@ -1818,18 +2076,17 @@ MmpCreateSection(PVOID ObjectBody, POBJECT_ATTRIBUTES ObjectAttributes) { DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n", - ObjectBody, Parent, RemainingPath); + ObjectBody, Parent, RemainingPath); if (RemainingPath == NULL) { - return(STATUS_SUCCESS); + return(STATUS_SUCCESS); } if (wcschr(RemainingPath+1, L'\\') != NULL) { return(STATUS_UNSUCCESSFUL); } - return(STATUS_SUCCESS); } @@ -1862,7 +2119,7 @@ MmCreatePhysicalMemorySection(VOID) if (!NT_SUCCESS(Status)) { DbgPrint("Failed to create PhysicalMemory section\n"); - KeBugCheck(0); + KEBUGCHECK(0); } Status = ObReferenceObjectByHandle(PhysSectionH, SECTION_ALL_ACCESS, @@ -1873,7 +2130,7 @@ MmCreatePhysicalMemorySection(VOID) if (!NT_SUCCESS(Status)) { DbgPrint("Failed to reference PhysicalMemory section\n"); - KeBugCheck(0); + KEBUGCHECK(0); } PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY; ObDereferenceObject((PVOID)PhysSection); @@ -1944,7 +2201,7 @@ MmCreatePageFileSection(PHANDLE SectionHandle, /* * Create the section */ - Status = ObCreateObject(SectionHandle, + Status = ObRosCreateObject(SectionHandle, DesiredAccess, ObjectAttributes, MmSectionObjectType, @@ -1961,7 +2218,6 @@ MmCreatePageFileSection(PHANDLE SectionHandle, Section->AllocationAttributes = AllocationAttributes; InitializeListHead(&Section->ViewListHead); KeInitializeSpinLock(&Section->ViewListLock); - KeInitializeMutex(&Section->Lock, 0); Section->FileObject = NULL; Section->MaximumSize = MaximumSize; Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), @@ -1972,15 +2228,16 @@ MmCreatePageFileSection(PHANDLE SectionHandle, ObDereferenceObject(Section); return(STATUS_NO_MEMORY); } - Section->Segments = Segment; + Section->Segment = Segment; Segment->ReferenceCount = 1; - KeInitializeMutex(&Segment->Lock, 0); + ExInitializeFastMutex(&Segment->Lock); Segment->FileOffset = 0; Segment->Protection = SectionPageProtection; Segment->Attributes = AllocationAttributes; Segment->Length = MaximumSize.u.LowPart; Segment->Flags = MM_PAGEFILE_SEGMENT; Segment->WriteCopy = FALSE; + ObDereferenceObject(Section); return(STATUS_SUCCESS); } @@ -2003,6 +2260,9 @@ MmCreateDataFileSection(PHANDLE SectionHandle, PFILE_OBJECT FileObject; PMM_SECTION_SEGMENT Segment; ULONG FileAccess; + IO_STATUS_BLOCK Iosb; + LARGE_INTEGER Offset; + CHAR Buffer; /* * Check the protection @@ -2012,11 +2272,31 @@ MmCreateDataFileSection(PHANDLE SectionHandle, { return(STATUS_INVALID_PAGE_PROTECTION); } - + + /* + * Read a bit so caching is initiated for the file object. + * This is only needed because MiReadPage currently cannot + * handle non-cached streams. + */ + Offset.QuadPart = 0; + Status = ZwReadFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + &Buffer, + sizeof (Buffer), + &Offset, + 0); + if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE)) + { + return(Status); + } + /* * Create the section */ - Status = ObCreateObject(SectionHandle, + Status = ObRosCreateObject(SectionHandle, DesiredAccess, ObjectAttributes, MmSectionObjectType, @@ -2033,18 +2313,6 @@ MmCreateDataFileSection(PHANDLE SectionHandle, Section->AllocationAttributes = AllocationAttributes; InitializeListHead(&Section->ViewListHead); KeInitializeSpinLock(&Section->ViewListLock); - KeInitializeMutex(&Section->Lock, 0); - Section->NrSegments = 1; - Section->ImageBase = NULL; - Section->EntryPoint = NULL; - Section->StackReserve = 0; - Section->StackCommit = 0; - Section->Subsystem = 0; - Section->MinorSubsystemVersion = 0; - Section->MajorSubsystemVersion = 0; - Section->ImageCharacteristics = 0; - Section->Machine = 0; - Section->Executable = FALSE; /* * Check file access required @@ -2098,11 +2366,11 @@ MmCreateDataFileSection(PHANDLE SectionHandle, else { MaximumSize = - ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize; + ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize; } if (MaximumSize.QuadPart > - ((PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart) + ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize.QuadPart) { IO_STATUS_BLOCK Iosb; Status = NtSetInformationFile(FileHandle, @@ -2139,7 +2407,7 @@ MmCreateDataFileSection(PHANDLE SectionHandle, * If this file hasn't been mapped as a data file before then allocate a * section segment to describe the data file mapping */ - if (FileObject->SectionObjectPointers->DataSectionObject == NULL) + if (FileObject->SectionObjectPointer->DataSectionObject == NULL) { Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), TAG_MM_SECTION_SEGMENT); @@ -2151,28 +2419,14 @@ MmCreateDataFileSection(PHANDLE SectionHandle, ObDereferenceObject(FileObject); return(STATUS_NO_MEMORY); } - Section->Segments = Segment; + Section->Segment = Segment; Segment->ReferenceCount = 1; - KeInitializeMutex(&Segment->Lock, 0); - + ExInitializeFastMutex(&Segment->Lock); /* * Set the lock before assigning the segment to the file object */ - Status = KeWaitForSingleObject((PVOID)&Segment->Lock, - 0, - KernelMode, - FALSE, - NULL); - if (Status != STATUS_SUCCESS) - { - KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); - ExFreePool(Segment); - ZwClose(*SectionHandle); - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - return(Status); - } - FileObject->SectionObjectPointers->DataSectionObject = (PVOID)Segment; + ExAcquireFastMutex(&Segment->Lock); + FileObject->SectionObjectPointer->DataSectionObject = (PVOID)Segment; Segment->FileOffset = 0; Segment->Protection = 0; @@ -2182,11 +2436,12 @@ MmCreateDataFileSection(PHANDLE SectionHandle, Segment->WriteCopy = FALSE; if (AllocationAttributes & SEC_RESERVE) { - Segment->Length = 0; + Segment->Length = Segment->RawLength = 0; } else { - Segment->Length = MaximumSize.u.LowPart; + Segment->RawLength = MaximumSize.u.LowPart; + Segment->Length = PAGE_ROUND_UP(Segment->RawLength); } Segment->VirtualAddress = NULL; } @@ -2197,36 +2452,24 @@ MmCreateDataFileSection(PHANDLE SectionHandle, * to extend it */ Segment = - (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointers-> + (PMM_SECTION_SEGMENT)FileObject->SectionObjectPointer-> DataSectionObject; - Section->Segments = Segment; + Section->Segment = Segment; InterlockedIncrement((PLONG)&Segment->ReferenceCount); - Status = KeWaitForSingleObject((PVOID)&Segment->Lock, - 0, - KernelMode, - FALSE, - NULL); - if (Status != STATUS_SUCCESS) - { - InterlockedDecrement((PLONG)&Segment->ReferenceCount); - KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); - ZwClose(*SectionHandle); - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - return(Status); - } - if (MaximumSize.u.LowPart > Segment->Length && + MmLockSectionSegment(Segment); + + if (MaximumSize.u.LowPart > Segment->RawLength && !(AllocationAttributes & SEC_RESERVE)) { - Segment->Length = MaximumSize.u.LowPart; + Segment->RawLength = MaximumSize.u.LowPart; + Segment->Length = PAGE_ROUND_UP(Segment->RawLength); } } - KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); - CcRosReferenceCache(FileObject); + MmUnlockSectionSegment(Segment); Section->FileObject = FileObject; Section->MaximumSize = MaximumSize; - KeReleaseMutex(&Segment->Lock, FALSE); - + CcRosReferenceCache(FileObject); + KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); ObDereferenceObject(Section); return(STATUS_SUCCESS); } @@ -2263,7 +2506,6 @@ MmCreateImageSection(PHANDLE SectionHandle, PSECTION_OBJECT Section; NTSTATUS Status; PFILE_OBJECT FileObject; - ULONG FileAccess; IMAGE_DOS_HEADER DosHeader; IO_STATUS_BLOCK Iosb; LARGE_INTEGER Offset; @@ -2272,7 +2514,10 @@ MmCreateImageSection(PHANDLE SectionHandle, PMM_SECTION_SEGMENT SectionSegments; ULONG NrSegments; PMM_IMAGE_SECTION_OBJECT ImageSectionObject; - + ULONG i; + ULONG Size; + ULONG Characteristics; + ULONG FileAccess = 0; /* * Check the protection */ @@ -2291,145 +2536,6 @@ MmCreateImageSection(PHANDLE SectionHandle, } /* - * Read the dos header - */ - Offset.QuadPart = 0; - Status = ZwReadFile(FileHandle, - NULL, - NULL, - NULL, - &Iosb, - &DosHeader, - sizeof(DosHeader), - &Offset, - 0); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - if (Iosb.Information != sizeof(DosHeader)) - { - return(STATUS_INVALID_IMAGE_FORMAT); - } - - /* - * Check the DOS signature - */ - if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) - { - return(STATUS_INVALID_IMAGE_FORMAT); - } - - /* - * Read the PE header - */ - Offset.QuadPart = DosHeader.e_lfanew; - Status = ZwReadFile(FileHandle, - NULL, - NULL, - NULL, - &Iosb, - &PEHeader, - sizeof(PEHeader), - &Offset, - 0); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - if (Iosb.Information != sizeof(PEHeader)) - { - return(STATUS_INVALID_IMAGE_FORMAT); - } - - /* - * Check the signature - */ - if (PEHeader.Signature != IMAGE_NT_SIGNATURE) - { - return(STATUS_INVALID_IMAGE_FORMAT); - } - - /* - * Read in the section headers - */ - Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader); - ImageSections = - ExAllocatePool(NonPagedPool, - PEHeader.FileHeader.NumberOfSections * - sizeof(IMAGE_SECTION_HEADER)); - Status = ZwReadFile(FileHandle, - NULL, - NULL, - NULL, - &Iosb, - ImageSections, - PEHeader.FileHeader.NumberOfSections * - sizeof(IMAGE_SECTION_HEADER), - &Offset, - 0); - if (!NT_SUCCESS(Status)) - { - ExFreePool(ImageSections); - return(Status); - } - if (Iosb.Information != - (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER))) - { - ExFreePool(ImageSections); - return(STATUS_INVALID_IMAGE_FORMAT); - } - - /* - * Create the section - */ - Status = ObCreateObject(SectionHandle, - DesiredAccess, - ObjectAttributes, - MmSectionObjectType, - (PVOID*)&Section); - if (!NT_SUCCESS(Status)) - { - ExFreePool(ImageSections); - return(Status); - } - - /* - * Initialize it - */ - Section->SectionPageProtection = SectionPageProtection; - Section->AllocationAttributes = AllocationAttributes; - InitializeListHead(&Section->ViewListHead); - KeInitializeSpinLock(&Section->ViewListLock); - KeInitializeMutex(&Section->Lock, 0); - Section->NrSegments = PEHeader.FileHeader.NumberOfSections + 1; - Section->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase; - Section->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint; - Section->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve; - Section->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit; - Section->Subsystem = PEHeader.OptionalHeader.Subsystem; - Section->MinorSubsystemVersion = - PEHeader.OptionalHeader.MinorSubsystemVersion; - Section->MajorSubsystemVersion = - PEHeader.OptionalHeader.MajorSubsystemVersion; - Section->ImageCharacteristics = PEHeader.FileHeader.Characteristics; - Section->Machine = PEHeader.FileHeader.Machine; - Section->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0); - - /* - * Check file access required - */ - if (SectionPageProtection & PAGE_READWRITE || - SectionPageProtection & PAGE_EXECUTE_READWRITE) - { - FileAccess = FILE_READ_DATA | FILE_WRITE_DATA; - } - else - { - FileAccess = FILE_READ_DATA; - } - - /* * Reference the file handle */ Status = ObReferenceObjectByHandle(FileHandle, @@ -2440,182 +2546,371 @@ MmCreateImageSection(PHANDLE SectionHandle, NULL); if (!NT_SUCCESS(Status)) { - ZwClose(*SectionHandle); - ObDereferenceObject(Section); - ExFreePool(ImageSections); - return(Status); + return Status; } /* - * We can't do memory mappings if the file system doesn't support the - * standard FCB + * Initialized caching for this file object if previously caching + * was initialized for the same on disk file */ - if (!(FileObject->Flags & FO_FCB_IS_VALID)) - { - ZwClose(*SectionHandle); - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - ExFreePool(ImageSections); - return(STATUS_INVALID_FILE_FOR_SECTION); - } + Status = CcTryToInitializeFileCache(FileObject); - /* - * Lock the file - */ - Status = KeWaitForSingleObject((PVOID)&FileObject->Lock, - 0, - KernelMode, - FALSE, - NULL); - if (Status != STATUS_SUCCESS) + if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL) { - ZwClose(*SectionHandle); - ObDereferenceObject(Section); - ObDereferenceObject(FileObject); - ExFreePool(ImageSections); - return(Status); - } + /* + * Read the dos header and check the DOS signature + */ + Offset.QuadPart = 0; + Status = ZwReadFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + &DosHeader, + sizeof(DosHeader), + &Offset, + 0); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(FileObject); + return(Status); + } + + /* + * Check the DOS signature + */ + if (Iosb.Information != sizeof(DosHeader) || + DosHeader.e_magic != IMAGE_DOS_SIGNATURE) + { + ObDereferenceObject(FileObject); + return(STATUS_INVALID_IMAGE_FORMAT); + } + + /* + * Read the PE header + */ + Offset.QuadPart = DosHeader.e_lfanew; + Status = ZwReadFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + &PEHeader, + sizeof(PEHeader), + &Offset, + 0); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(FileObject); + return(Status); + } - /* - * If this file hasn't been mapped as a image file before then allocate the - * section segments to describe the mapping - */ - NrSegments = PEHeader.FileHeader.NumberOfSections + 1; - if (FileObject->SectionObjectPointers->ImageSectionObject == NULL) - { - ULONG i; - ULONG Size; - ULONG Characteristics; - - Size = sizeof(MM_IMAGE_SECTION_OBJECT) + - (sizeof(MM_SECTION_SEGMENT) * NrSegments); - ImageSectionObject = - ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT); - if (ImageSectionObject == NULL) - { - KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); - ZwClose(*SectionHandle); - ObDereferenceObject(Section); + /* + * Check the signature + */ + if (Iosb.Information != sizeof(PEHeader) || + PEHeader.Signature != IMAGE_NT_SIGNATURE) + { + ObDereferenceObject(FileObject); + return(STATUS_INVALID_IMAGE_FORMAT); + } + + /* + * Read in the section headers + */ + Offset.QuadPart = DosHeader.e_lfanew + sizeof(PEHeader); + ImageSections = ExAllocatePool(NonPagedPool, + PEHeader.FileHeader.NumberOfSections * + sizeof(IMAGE_SECTION_HEADER)); + if (ImageSections == NULL) + { ObDereferenceObject(FileObject); - ExFreePool(ImageSections); return(STATUS_NO_MEMORY); } - ImageSectionObject->NrSegments = NrSegments; - SectionSegments = ImageSectionObject->Segments; - Section->Segments = SectionSegments; - - SectionSegments[0].FileOffset = 0; - SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA; - SectionSegments[0].Protection = PAGE_READWRITE; - SectionSegments[0].RawLength = PAGE_SIZE; - SectionSegments[0].Length = PAGE_SIZE; - SectionSegments[0].Flags = 0; - SectionSegments[0].ReferenceCount = 1; - SectionSegments[0].VirtualAddress = 0; - SectionSegments[0].WriteCopy = TRUE; - KeInitializeMutex(&SectionSegments[0].Lock, 0); - - for (i = 1; i < NrSegments; i++) - { - SectionSegments[i].FileOffset = - ImageSections[i-1].PointerToRawData; - SectionSegments[i].Characteristics = - ImageSections[i-1].Characteristics; - /* - * Set up the protection and write copy variables. - */ - Characteristics = ImageSections[i - 1].Characteristics; - if ((Characteristics & IMAGE_SECTION_CHAR_READABLE) || - (Characteristics & IMAGE_SECTION_CHAR_WRITABLE) || - (Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE)) - { - SectionSegments[i].Protection = - SectionCharacteristicsToProtect[Characteristics >> 28]; - SectionSegments[i].WriteCopy = - !(Characteristics & IMAGE_SECTION_CHAR_SHARED); - } - else if (Characteristics & IMAGE_SECTION_CHAR_CODE) - { - SectionSegments[i].Protection = PAGE_EXECUTE_READ; - SectionSegments[i].WriteCopy = TRUE; - } - else if (Characteristics & IMAGE_SECTION_CHAR_DATA) - { - SectionSegments[i].Protection = PAGE_READWRITE; - SectionSegments[i].WriteCopy = TRUE; - } - else if (Characteristics & IMAGE_SECTION_CHAR_BSS) - { - SectionSegments[i].Protection = PAGE_READWRITE; - SectionSegments[i].WriteCopy = TRUE; - } - else - { - SectionSegments[i].Protection = PAGE_NOACCESS; - SectionSegments[i].WriteCopy = TRUE; - } - - /* - * Set up the attributes. - */ - if (Characteristics & IMAGE_SECTION_CHAR_CODE) - { - SectionSegments[i].Attributes = 0; - } - else if (Characteristics & IMAGE_SECTION_CHAR_DATA) - { - SectionSegments[i].Attributes = 0; - } - else if (Characteristics & IMAGE_SECTION_CHAR_BSS) - { - SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS; - } - else - { - SectionSegments[i].Attributes = 0; - } + Status = ZwReadFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + ImageSections, + PEHeader.FileHeader.NumberOfSections * + sizeof(IMAGE_SECTION_HEADER), + &Offset, + 0); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(FileObject); + ExFreePool(ImageSections); + return(Status); + } + if (Iosb.Information != (PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER))) + { + ObDereferenceObject(FileObject); + ExFreePool(ImageSections); + return(STATUS_INVALID_IMAGE_FORMAT); + } - SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData; - SectionSegments[i].Length = - ImageSections[i-1].Misc.VirtualSize; - SectionSegments[i].Flags = 0; - SectionSegments[i].ReferenceCount = 1; - SectionSegments[i].VirtualAddress = - (PVOID)ImageSections[i-1].VirtualAddress; - KeInitializeMutex(&SectionSegments[i].Lock, 0); - } + /* + * Create the section + */ + Status = ObRosCreateObject(SectionHandle, + DesiredAccess, + ObjectAttributes, + MmSectionObjectType, + (PVOID*)&Section); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(FileObject); + ExFreePool(ImageSections); + return(Status); + } + + /* + * Initialize it + */ + Section->SectionPageProtection = SectionPageProtection; + Section->AllocationAttributes = AllocationAttributes; + InitializeListHead(&Section->ViewListHead); + KeInitializeSpinLock(&Section->ViewListLock); - FileObject->SectionObjectPointers->ImageSectionObject = - (PVOID)ImageSectionObject; + /* + * Check file access required + */ + if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) + { + FileAccess = FILE_READ_DATA | FILE_WRITE_DATA; + } + else + { + FileAccess = FILE_READ_DATA; + } + + /* + * We can't do memory mappings if the file system doesn't support the + * standard FCB + */ + if (!(FileObject->Flags & FO_FCB_IS_VALID)) + { + ZwClose(*SectionHandle); + ObDereferenceObject(Section); + ObDereferenceObject(FileObject); + ExFreePool(ImageSections); + return(STATUS_INVALID_FILE_FOR_SECTION); + } + + /* + * Lock the file + */ + Status = KeWaitForSingleObject((PVOID)&FileObject->Lock, + 0, + KernelMode, + FALSE, + NULL); + if (Status != STATUS_SUCCESS) + { + ZwClose(*SectionHandle); + ObDereferenceObject(Section); + ObDereferenceObject(FileObject); + ExFreePool(ImageSections); + return(Status); + } + + /* + * allocate the section segments to describe the mapping + */ + NrSegments = PEHeader.FileHeader.NumberOfSections + 1; + Size = sizeof(MM_IMAGE_SECTION_OBJECT) + sizeof(MM_SECTION_SEGMENT) * NrSegments; + ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MM_SECTION_SEGMENT); + if (ImageSectionObject == NULL) + { + KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); + ZwClose(*SectionHandle); + ObDereferenceObject(Section); + ObDereferenceObject(FileObject); + ExFreePool(ImageSections); + return(STATUS_NO_MEMORY); + } + Section->ImageSection = ImageSectionObject; + ImageSectionObject->NrSegments = NrSegments; + ImageSectionObject->ImageBase = (PVOID)PEHeader.OptionalHeader.ImageBase; + ImageSectionObject->EntryPoint = (PVOID)PEHeader.OptionalHeader.AddressOfEntryPoint; + ImageSectionObject->StackReserve = PEHeader.OptionalHeader.SizeOfStackReserve; + ImageSectionObject->StackCommit = PEHeader.OptionalHeader.SizeOfStackCommit; + ImageSectionObject->Subsystem = PEHeader.OptionalHeader.Subsystem; + ImageSectionObject->MinorSubsystemVersion = PEHeader.OptionalHeader.MinorSubsystemVersion; + ImageSectionObject->MajorSubsystemVersion = PEHeader.OptionalHeader.MajorSubsystemVersion; + ImageSectionObject->ImageCharacteristics = PEHeader.FileHeader.Characteristics; + ImageSectionObject->Machine = PEHeader.FileHeader.Machine; + ImageSectionObject->Executable = (PEHeader.OptionalHeader.SizeOfCode != 0); + + SectionSegments = ImageSectionObject->Segments; + SectionSegments[0].FileOffset = 0; + SectionSegments[0].Characteristics = IMAGE_SECTION_CHAR_DATA; + SectionSegments[0].Protection = PAGE_READONLY; + SectionSegments[0].RawLength = PAGE_SIZE; + SectionSegments[0].Length = PAGE_SIZE; + SectionSegments[0].Flags = 0; + SectionSegments[0].ReferenceCount = 1; + SectionSegments[0].VirtualAddress = 0; + SectionSegments[0].WriteCopy = FALSE; + ExInitializeFastMutex(&SectionSegments[0].Lock); + for (i = 1; i < NrSegments; i++) + { + SectionSegments[i].FileOffset = ImageSections[i-1].PointerToRawData; + SectionSegments[i].Characteristics = ImageSections[i-1].Characteristics; + + /* + * Set up the protection and write copy variables. + */ + Characteristics = ImageSections[i - 1].Characteristics; + if (Characteristics & (IMAGE_SECTION_CHAR_READABLE|IMAGE_SECTION_CHAR_WRITABLE|IMAGE_SECTION_CHAR_EXECUTABLE)) + { + SectionSegments[i].Protection = SectionCharacteristicsToProtect[Characteristics >> 28]; + SectionSegments[i].WriteCopy = !(Characteristics & IMAGE_SECTION_CHAR_SHARED); + } + else if (Characteristics & IMAGE_SECTION_CHAR_CODE) + { + SectionSegments[i].Protection = PAGE_EXECUTE_READ; + SectionSegments[i].WriteCopy = TRUE; + } + else if (Characteristics & IMAGE_SECTION_CHAR_DATA) + { + SectionSegments[i].Protection = PAGE_READWRITE; + SectionSegments[i].WriteCopy = TRUE; + } + else if (Characteristics & IMAGE_SECTION_CHAR_BSS) + { + SectionSegments[i].Protection = PAGE_READWRITE; + SectionSegments[i].WriteCopy = TRUE; + } + else + { + SectionSegments[i].Protection = PAGE_NOACCESS; + SectionSegments[i].WriteCopy = TRUE; + } + + /* + * Set up the attributes. + */ + if (Characteristics & IMAGE_SECTION_CHAR_CODE) + { + SectionSegments[i].Attributes = 0; + } + else if (Characteristics & IMAGE_SECTION_CHAR_DATA) + { + SectionSegments[i].Attributes = 0; + } + else if (Characteristics & IMAGE_SECTION_CHAR_BSS) + { + SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS; + } + else + { + SectionSegments[i].Attributes = 0; + } + + SectionSegments[i].RawLength = ImageSections[i-1].SizeOfRawData; + SectionSegments[i].Length = ImageSections[i-1].Misc.VirtualSize; + SectionSegments[i].Flags = 0; + SectionSegments[i].ReferenceCount = 1; + SectionSegments[i].VirtualAddress = (PVOID)ImageSections[i-1].VirtualAddress; + ExInitializeFastMutex(&SectionSegments[i].Lock); + } + if (0 != InterlockedCompareExchange((PLONG)&FileObject->SectionObjectPointer->ImageSectionObject, + (LONG)ImageSectionObject, 0)) + { + /* + * An other thread has initialized the some image in the background + */ + ExFreePool(ImageSectionObject); + ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; + Section->ImageSection = ImageSectionObject; + SectionSegments = ImageSectionObject->Segments; + + for (i = 0; i < NrSegments; i++) + { + InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount); + } + } + ExFreePool(ImageSections); } else { - ULONG i; + /* + * Create the section + */ + Status = ObRosCreateObject(SectionHandle, + DesiredAccess, + ObjectAttributes, + MmSectionObjectType, + (PVOID*)&Section); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(FileObject); + return(Status); + } + + /* + * Initialize it + */ + Section->SectionPageProtection = SectionPageProtection; + Section->AllocationAttributes = AllocationAttributes; + InitializeListHead(&Section->ViewListHead); + KeInitializeSpinLock(&Section->ViewListLock); - ImageSectionObject = (PMM_IMAGE_SECTION_OBJECT) - FileObject->SectionObjectPointers->ImageSectionObject; + /* + * Check file access required + */ + if (SectionPageProtection & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE)) + { + FileAccess = FILE_READ_DATA | FILE_WRITE_DATA; + } + else + { + FileAccess = FILE_READ_DATA; + } + + /* + * Lock the file + */ + Status = KeWaitForSingleObject((PVOID)&FileObject->Lock, + 0, + KernelMode, + FALSE, + NULL); + if (Status != STATUS_SUCCESS) + { + ZwClose(*SectionHandle); + ObDereferenceObject(Section); + ObDereferenceObject(FileObject); + return(Status); + } + + ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; + Section->ImageSection = ImageSectionObject; SectionSegments = ImageSectionObject->Segments; - Section->Segments = SectionSegments; + NrSegments = ImageSectionObject->NrSegments; /* * Otherwise just reference all the section segments */ for (i = 0; i < NrSegments; i++) { - InterlockedIncrement(&SectionSegments[i].ReferenceCount); + InterlockedIncrement((LONG *)&SectionSegments[i].ReferenceCount); } } - ExFreePool(ImageSections); - KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); - CcRosReferenceCache(FileObject); Section->FileObject = FileObject; - + CcRosReferenceCache(FileObject); + KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE); ObDereferenceObject(Section); return(STATUS_SUCCESS); } +/* + * @implemented + */ NTSTATUS STDCALL NtCreateSection (OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, @@ -2673,26 +2968,25 @@ NtCreateSection (OUT PHANDLE SectionHandle, * RETURN VALUE * * REVISIONS - * */ NTSTATUS STDCALL NtOpenSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) { - NTSTATUS Status; - - *SectionHandle = 0; + NTSTATUS Status; - Status = ObOpenObjectByName(ObjectAttributes, - MmSectionObjectType, - NULL, - UserMode, - DesiredAccess, - NULL, - SectionHandle); + *SectionHandle = 0; - return(Status); + Status = ObOpenObjectByName(ObjectAttributes, + MmSectionObjectType, + NULL, + UserMode, + DesiredAccess, + NULL, + SectionHandle); + + return(Status); } NTSTATUS STATIC @@ -2703,32 +2997,34 @@ MmMapViewOfSegment(PEPROCESS Process, PVOID* BaseAddress, ULONG ViewSize, ULONG Protect, - ULONG ViewOffset) + ULONG ViewOffset, + BOOL TopDown) { PMEMORY_AREA MArea; NTSTATUS Status; KIRQL oldIrql; Status = MmCreateMemoryArea(Process, - &Process->AddressSpace, + AddressSpace, MEMORY_AREA_SECTION_VIEW, BaseAddress, ViewSize, Protect, &MArea, - FALSE); + FALSE, + TopDown); if (!NT_SUCCESS(Status)) { DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n", (*BaseAddress), (*BaseAddress) + ViewSize); return(Status); } - + KeAcquireSpinLock(&Section->ViewListLock, &oldIrql); - InsertTailList(&Section->ViewListHead, + InsertTailList(&Section->ViewListHead, &MArea->Data.SectionData.ViewListEntry); KeReleaseSpinLock(&Section->ViewListLock, oldIrql); - + ObReferenceObjectByPointer((PVOID)Section, SECTION_MAP_READ, NULL, @@ -2739,7 +3035,7 @@ MmMapViewOfSegment(PEPROCESS Process, MArea->Data.SectionData.WriteCopyView = FALSE; MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead, ViewSize, 0, Protect); - + return(STATUS_SUCCESS); } @@ -2790,6 +3086,8 @@ MmMapViewOfSegment(PEPROCESS Process, * * RETURN VALUE * Status. + * + * @implemented */ NTSTATUS STDCALL NtMapViewOfSection(HANDLE SectionHandle, @@ -2859,39 +3157,78 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, PMEMORY_AREA MArea; ULONG Entry; PFILE_OBJECT FileObject; - PREACTOS_COMMON_FCB_HEADER Fcb; + PBCB Bcb; ULONG Offset; SWAPENTRY SavedSwapEntry; PMM_PAGEOP PageOp; + LARGE_INTEGER Timeout; + NTSTATUS Status; + PSECTION_OBJECT Section; + PMM_SECTION_SEGMENT Segment; MArea = (PMEMORY_AREA)Context; - Offset = ((ULONG)PAGE_ROUND_DOWN(Address) - (ULONG)MArea->BaseAddress) + - MArea->Data.SectionData.ViewOffset; - Entry = MmGetPageEntrySectionSegment(MArea->Data.SectionData.Segment, - Offset); + Address = (PVOID)PAGE_ROUND_DOWN(Address); + + Offset = ((ULONG)Address - (ULONG)MArea->BaseAddress); + + Section = MArea->Data.SectionData.Section; + Segment = MArea->Data.SectionData.Segment; + - PageOp = MmCheckForPageOp(MArea, 0, NULL, MArea->Data.SectionData.Segment, - Offset); - assert(PageOp == NULL); + PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset); + + while (PageOp) + { + MmUnlockSectionSegment(Segment); + MmUnlockAddressSpace(&MArea->Process->AddressSpace); + + Timeout.QuadPart = -100000000LL; // 10 sec + Status = KeWaitForSingleObject(&PageOp->CompletionEvent, + 0, + KernelMode, + FALSE, + &Timeout); + if (Status != STATUS_SUCCESS) + { + DPRINT1("Failed to wait for page op, status = %x\n", Status); + KEBUGCHECK(0); + } + + MmLockAddressSpace(&MArea->Process->AddressSpace); + MmLockSectionSegment(Segment); + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + PageOp = MmCheckForPageOp(MArea, 0, NULL, Segment, Offset); + } + Entry = MmGetPageEntrySectionSegment(Segment, Offset); + /* * For a dirty, datafile, non-private page mark it as dirty in the * cache manager. */ - if (MArea->Data.SectionData.Segment->Flags & MM_DATAFILE_SEGMENT) + if (Segment->Flags & MM_DATAFILE_SEGMENT) { if (PhysAddr.QuadPart == PAGE_FROM_SSE(Entry) && Dirty) { FileObject = MemoryArea->Data.SectionData.Section->FileObject; - Fcb = (PREACTOS_COMMON_FCB_HEADER)FileObject->FsContext; - CcRosMarkDirtyCacheSegment(Fcb->Bcb, Offset); + Bcb = FileObject->SectionObjectPointer->SharedCacheMap; + CcRosMarkDirtyCacheSegment(Bcb, Offset); assert(SwapEntry == 0); } } if (SwapEntry != 0) { + /* + * Sanity check + */ + if (Segment->Flags & MM_PAGEFILE_SEGMENT) + { + DPRINT1("Found a swap entry for a page in a pagefile section.\n"); + KEBUGCHECK(0); + } MmFreeSwapPage(SwapEntry); } else if (PhysAddr.QuadPart != 0) @@ -2899,6 +3236,14 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, if (IS_SWAP_FROM_SSE(Entry) || PhysAddr.QuadPart != (PAGE_FROM_SSE(Entry))) { + /* + * Sanity check + */ + if (Segment->Flags & MM_PAGEFILE_SEGMENT) + { + DPRINT1("Found a private page in a pagefile section.\n"); + KEBUGCHECK(0); + } /* * Just dereference private pages */ @@ -2908,38 +3253,31 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, MmFreeSwapPage(SavedSwapEntry); MmSetSavedSwapEntryPage(PhysAddr, 0); } - MmDeleteRmap(PhysAddr, MArea->Process, Address); - MmReleasePageMemoryConsumer(MC_USER, PhysAddr); + MmDeleteRmap(PhysAddr, MArea->Process, Address); + MmReleasePageMemoryConsumer(MC_USER, PhysAddr); } else { - MmUnsharePageEntrySectionSegment(MArea->Data.SectionData.Section, - MArea->Data.SectionData.Segment, - Offset, - Dirty); - MmDeleteRmap(PhysAddr, MArea->Process, Address); - MmReleasePageMemoryConsumer(MC_USER, PhysAddr); + MmDeleteRmap(PhysAddr, MArea->Process, Address); + MmUnsharePageEntrySectionSegment(Section, Segment, Offset, Dirty); + MmReleasePageMemoryConsumer(MC_USER, PhysAddr); } } } -NTSTATUS STDCALL -MmUnmapViewOfSection(PEPROCESS Process, +NTSTATUS +MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace, PVOID BaseAddress) { - NTSTATUS Status; + NTSTATUS Status; PMEMORY_AREA MemoryArea; - PMADDRESS_SPACE AddressSpace; PSECTION_OBJECT Section; PMM_SECTION_SEGMENT Segment; KIRQL oldIrql; PLIST_ENTRY CurrentEntry; PMM_REGION CurrentRegion; - - AddressSpace = &Process->AddressSpace; - - DPRINT("Opening memory area Process %x BaseAddress %x\n", - Process, BaseAddress); + PLIST_ENTRY RegionListHead; + MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress); if (MemoryArea == NULL) @@ -2948,47 +3286,120 @@ MmUnmapViewOfSection(PEPROCESS Process, } MemoryArea->DeleteInProgress = TRUE; - - MmLockSection(MemoryArea->Data.SectionData.Section); - MmLockSectionSegment(MemoryArea->Data.SectionData.Segment); Section = MemoryArea->Data.SectionData.Section; Segment = MemoryArea->Data.SectionData.Segment; + + MmLockSectionSegment(Segment); KeAcquireSpinLock(&Section->ViewListLock, &oldIrql); RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry); KeReleaseSpinLock(&Section->ViewListLock, oldIrql); - CurrentEntry = MemoryArea->Data.SectionData.RegionListHead.Flink; - while (CurrentEntry != &MemoryArea->Data.SectionData.RegionListHead) + RegionListHead = &MemoryArea->Data.SectionData.RegionListHead; + while (!IsListEmpty(RegionListHead)) { - CurrentRegion = - CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry); - CurrentEntry = CurrentEntry->Flink; + CurrentEntry = RemoveHeadList(RegionListHead); + CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry); ExFreePool(CurrentRegion); } - if (MemoryArea->Data.SectionData.Section->AllocationAttributes & - SEC_PHYSICALMEMORY) + if (Section->AllocationAttributes & SEC_PHYSICALMEMORY) { - Status = MmFreeMemoryArea(&Process->AddressSpace, - BaseAddress, + Status = MmFreeMemoryArea(AddressSpace, + BaseAddress, 0, NULL, NULL); } else { - Status = MmFreeMemoryArea(&Process->AddressSpace, + Status = MmFreeMemoryArea(AddressSpace, BaseAddress, 0, MmFreeSectionPage, MemoryArea); - } - MmUnlockSection(Section); + } MmUnlockSectionSegment(Segment); ObDereferenceObject(Section); return(STATUS_SUCCESS); } +/* + * @implemented + */ +NTSTATUS STDCALL +MmUnmapViewOfSection(PEPROCESS Process, + PVOID BaseAddress) +{ + NTSTATUS Status; + PMEMORY_AREA MemoryArea; + PMADDRESS_SPACE AddressSpace; + PSECTION_OBJECT Section; + + DPRINT("Opening memory area Process %x BaseAddress %x\n", + Process, BaseAddress); + + assert(Process); + + AddressSpace = &Process->AddressSpace; + MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, + BaseAddress); + if (MemoryArea == NULL) + { + return(STATUS_UNSUCCESSFUL); + } + + Section = MemoryArea->Data.SectionData.Section; + + if (Section->AllocationAttributes & SEC_IMAGE) + { + ULONG i; + ULONG NrSegments; + PMM_IMAGE_SECTION_OBJECT ImageSectionObject; + PMM_SECTION_SEGMENT SectionSegments; + PVOID ImageBaseAddress; + PMM_SECTION_SEGMENT Segment; + + Segment = MemoryArea->Data.SectionData.Segment; + ImageSectionObject = Section->ImageSection; + SectionSegments = ImageSectionObject->Segments; + NrSegments = ImageSectionObject->NrSegments; + + /* Search for the current segment within the section segments + * and calculate the image base address */ + for (i = 0; i < NrSegments; i++) + { + if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD)) + { + if (Segment == &SectionSegments[i]) + { + ImageBaseAddress = BaseAddress - (ULONG_PTR)SectionSegments[i].VirtualAddress; + break; + } + } + } + if (i >= NrSegments) + { + KEBUGCHECK(0); + } + + for (i = 0; i < NrSegments; i++) + { + if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD)) + { + PVOID SBaseAddress = (PVOID) + (ImageBaseAddress + (ULONG_PTR)SectionSegments[i].VirtualAddress); + + Status = MmUnmapViewOfSegment(AddressSpace, SBaseAddress); + } + } + } + else + { + Status = MmUnmapViewOfSegment(AddressSpace, BaseAddress); + } + return(STATUS_SUCCESS); +} + /********************************************************************** * NAME EXPORTED * NtUnmapViewOfSection @@ -3004,7 +3415,6 @@ MmUnmapViewOfSection(PEPROCESS Process, * Status. * * REVISIONS - * */ NTSTATUS STDCALL NtUnmapViewOfSection (HANDLE ProcessHandle, @@ -3104,23 +3514,24 @@ NtQuerySection (IN HANDLE SectionHandle, ObDereferenceObject(Section); return(STATUS_INFO_LENGTH_MISMATCH); } + Sii = (PSECTION_IMAGE_INFORMATION)SectionInformation; - Sii->EntryPoint = Section->EntryPoint; - Sii->Unknown1 = 0; - Sii->StackReserve = Section->StackReserve; - Sii->StackCommit = Section->StackCommit; - Sii->Subsystem = Section->Subsystem; - Sii->MinorSubsystemVersion = Section->MinorSubsystemVersion; - Sii->MajorSubsystemVersion = Section->MajorSubsystemVersion; - Sii->Unknown2 = 0; - Sii->Characteristics = Section->ImageCharacteristics; - Sii->ImageNumber = Section->Machine; - Sii->Executable = Section->Executable; - Sii->Unknown3 = 0; - Sii->Unknown4[0] = 0; - Sii->Unknown4[1] = 0; - Sii->Unknown4[2] = 0; - + memset(Sii, 0, sizeof(SECTION_IMAGE_INFORMATION)); + if (Section->AllocationAttributes & SEC_IMAGE) + { + PMM_IMAGE_SECTION_OBJECT ImageSectionObject; + ImageSectionObject = Section->ImageSection; + + Sii->EntryPoint = ImageSectionObject->EntryPoint; + Sii->StackReserve = ImageSectionObject->StackReserve; + Sii->StackCommit = ImageSectionObject->StackCommit; + Sii->Subsystem = ImageSectionObject->Subsystem; + Sii->MinorSubsystemVersion = ImageSectionObject->MinorSubsystemVersion; + Sii->MajorSubsystemVersion = ImageSectionObject->MajorSubsystemVersion; + Sii->Characteristics = ImageSectionObject->ImageCharacteristics; + Sii->ImageNumber = ImageSectionObject->Machine; + Sii->Executable = ImageSectionObject->Executable; + } *ResultLength = sizeof(SECTION_IMAGE_INFORMATION); Status = STATUS_SUCCESS; break; @@ -3140,6 +3551,7 @@ NtExtendSection(IN HANDLE SectionHandle, IN ULONG NewMaximumSize) { UNIMPLEMENTED; + return(STATUS_NOT_IMPLEMENTED); } @@ -3158,7 +3570,6 @@ NtExtendSection(IN HANDLE SectionHandle, * Code taken from ntoskrnl/mm/special.c. * * REVISIONS - * */ PVOID STDCALL MmAllocateSection (IN ULONG Length) @@ -3181,6 +3592,7 @@ MmAllocateSection (IN ULONG Length) Length, 0, &marea, + FALSE, FALSE); if (!NT_SUCCESS(Status)) { @@ -3189,7 +3601,7 @@ MmAllocateSection (IN ULONG Length) } MmUnlockAddressSpace(AddressSpace); DPRINT("Result %p\n",Result); - for (i = 0; (i <= (Length / PAGE_SIZE)); i++) + for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++) { PHYSICAL_ADDRESS Page; @@ -3197,7 +3609,7 @@ MmAllocateSection (IN ULONG Length) if (!NT_SUCCESS(Status)) { DbgPrint("Unable to allocate page\n"); - KeBugCheck(0); + KEBUGCHECK(0); } Status = MmCreateVirtualMapping (NULL, (Result + (i * PAGE_SIZE)), @@ -3206,8 +3618,8 @@ MmAllocateSection (IN ULONG Length) TRUE); if (!NT_SUCCESS(Status)) { - DbgPrint("Unable to create virtual mapping\n"); - KeBugCheck(0); + DbgPrint("Unable to create virtual mapping\n"); + KEBUGCHECK(0); } } return ((PVOID)Result); @@ -3260,6 +3672,8 @@ MmAllocateSection (IN ULONG Length) * * RETURN VALUE * Status. + * + * @implemented */ NTSTATUS STDCALL MmMapViewOfSection(IN PVOID SectionObject, @@ -3278,84 +3692,91 @@ MmMapViewOfSection(IN PVOID SectionObject, ULONG ViewOffset; NTSTATUS Status = STATUS_SUCCESS; + assert(Process); + Section = (PSECTION_OBJECT)SectionObject; AddressSpace = &Process->AddressSpace; MmLockAddressSpace(AddressSpace); - MmLockSection(SectionObject); - + if (Section->AllocationAttributes & SEC_IMAGE) { ULONG i; + ULONG NrSegments; PVOID ImageBase; - ULONG ImageSize; - + ULONG ImageSize; + PMM_IMAGE_SECTION_OBJECT ImageSectionObject; + PMM_SECTION_SEGMENT SectionSegments; + + ImageSectionObject = Section->ImageSection; + SectionSegments = ImageSectionObject->Segments; + NrSegments = ImageSectionObject->NrSegments; + + ImageBase = *BaseAddress; if (ImageBase == NULL) { - ImageBase = Section->ImageBase; + ImageBase = ImageSectionObject->ImageBase; } - + ImageSize = 0; - for (i = 0; i < Section->NrSegments; i++) + for (i = 0; i < NrSegments; i++) { - if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD)) + if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD)) { ULONG MaxExtent; - MaxExtent = (ULONG)(Section->Segments[i].VirtualAddress + - Section->Segments[i].Length); + MaxExtent = (ULONG)(SectionSegments[i].VirtualAddress + + SectionSegments[i].Length); ImageSize = max(ImageSize, MaxExtent); } } /* Check there is enough space to map the section at that point. */ if (MmOpenMemoryAreaByRegion(AddressSpace, ImageBase, - ImageSize) != NULL) + PAGE_ROUND_UP(ImageSize)) != NULL) { /* Fail if the user requested a fixed base address. */ if ((*BaseAddress) != NULL) { - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); - return(Status); + return(STATUS_UNSUCCESSFUL); } /* Otherwise find a gap to map the image. */ - ImageBase = MmFindGap(AddressSpace, ImageSize); + ImageBase = MmFindGap(AddressSpace, PAGE_ROUND_UP(ImageSize), FALSE); if (ImageBase == NULL) { - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); - return(Status); + return(STATUS_UNSUCCESSFUL); } } - - for (i = 0; i < Section->NrSegments; i++) + + for (i = 0; i < NrSegments; i++) { - PVOID SBaseAddress; - - if (!(Section->Segments[i].Characteristics & IMAGE_SECTION_NOLOAD)) + PVOID SBaseAddress; + + if (!(SectionSegments[i].Characteristics & IMAGE_SECTION_NOLOAD)) { SBaseAddress = (PVOID) - (ImageBase + (ULONG_PTR)Section->Segments[i].VirtualAddress); - - MmLockSectionSegment(&Section->Segments[i]); + (ImageBase + (ULONG_PTR)SectionSegments[i].VirtualAddress); + MmLockSectionSegment(&SectionSegments[i]); Status = MmMapViewOfSegment(Process, - &Process->AddressSpace, + AddressSpace, Section, - &Section->Segments[i], + &SectionSegments[i], &SBaseAddress, - Section->Segments[i].Length, - Section->Segments[i].Protection, - Section->Segments[i].FileOffset); - MmUnlockSectionSegment(&Section->Segments[i]); + SectionSegments[i].Length, + SectionSegments[i].Protection, + (ULONG_PTR)SectionSegments[i].VirtualAddress, + FALSE); + MmUnlockSectionSegment(&SectionSegments[i]); if (!NT_SUCCESS(Status)) { - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); return(Status); } } } + *BaseAddress = ImageBase; } else @@ -3368,10 +3789,9 @@ MmMapViewOfSection(IN PVOID SectionObject, { ViewOffset = SectionOffset->u.LowPart; } - + if ((ViewOffset % PAGE_SIZE) != 0) { - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); return(STATUS_MAPPED_ALIGNMENT); } @@ -3384,31 +3804,33 @@ MmMapViewOfSection(IN PVOID SectionObject, { (*ViewSize) = Section->MaximumSize.u.LowPart - ViewOffset; } - - MmLockSectionSegment(Section->Segments); + + MmLockSectionSegment(Section->Segment); Status = MmMapViewOfSegment(Process, - &Process->AddressSpace, + AddressSpace, Section, - Section->Segments, + Section->Segment, BaseAddress, *ViewSize, Protect, - ViewOffset); - MmUnlockSectionSegment(Section->Segments); + ViewOffset, + (AllocationType & MEM_TOP_DOWN)); + MmUnlockSectionSegment(Section->Segment); if (!NT_SUCCESS(Status)) { - MmUnlockSection(Section); - MmUnlockAddressSpace(AddressSpace); + MmUnlockAddressSpace(AddressSpace); return(Status); } } - MmUnlockSection(Section); MmUnlockAddressSpace(AddressSpace); return(STATUS_SUCCESS); } +/* + * @unimplemented + */ BOOLEAN STDCALL MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER NewFileSize) @@ -3418,6 +3840,9 @@ MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, } +/* + * @unimplemented + */ BOOLEAN STDCALL MmDisableModifiedWriteOfSection (DWORD Unknown0) { @@ -3425,14 +3850,32 @@ MmDisableModifiedWriteOfSection (DWORD Unknown0) return (FALSE); } +/* + * @implemented + */ BOOLEAN STDCALL MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN MMFLUSH_TYPE FlushType) { - UNIMPLEMENTED; - return (FALSE); + switch(FlushType) + { + case MmFlushForDelete: + if (SectionObjectPointer->ImageSectionObject || + SectionObjectPointer->DataSectionObject) + { + return FALSE; + } + CcRosSetRemoveOnClose(SectionObjectPointer); + return TRUE; + case MmFlushForWrite: + break; + } + return FALSE; } +/* + * @unimplemented + */ BOOLEAN STDCALL MmForceSectionClosed (DWORD Unknown0, DWORD Unknown1) @@ -3442,23 +3885,77 @@ MmForceSectionClosed (DWORD Unknown0, } +/* + * @implemented + */ NTSTATUS STDCALL -MmMapViewInSystemSpace (IN PVOID Section, +MmMapViewInSystemSpace (IN PVOID SectionObject, OUT PVOID * MappedBase, - IN PULONG ViewSize) + IN OUT PULONG ViewSize) { - UNIMPLEMENTED; - return (STATUS_NOT_IMPLEMENTED); + PSECTION_OBJECT Section; + PMADDRESS_SPACE AddressSpace; + NTSTATUS Status; + + DPRINT("MmMapViewInSystemSpace() called\n"); + + Section = (PSECTION_OBJECT)SectionObject; + AddressSpace = MmGetKernelAddressSpace(); + + MmLockAddressSpace(AddressSpace); + + + if ((*ViewSize) == 0) + { + (*ViewSize) = Section->MaximumSize.u.LowPart; + } + else if ((*ViewSize) > Section->MaximumSize.u.LowPart) + { + (*ViewSize) = Section->MaximumSize.u.LowPart; + } + + MmLockSectionSegment(Section->Segment); + + + Status = MmMapViewOfSegment(NULL, + AddressSpace, + Section, + Section->Segment, + MappedBase, + *ViewSize, + PAGE_READWRITE, + 0, + FALSE); + + MmUnlockSectionSegment(Section->Segment); + MmUnlockAddressSpace(AddressSpace); + + return Status; } + +/* + * @implemented + */ NTSTATUS STDCALL -MmUnmapViewInSystemSpace (DWORD Unknown0) +MmUnmapViewInSystemSpace (IN PVOID MappedBase) { - UNIMPLEMENTED; - return (STATUS_NOT_IMPLEMENTED); + PMADDRESS_SPACE AddressSpace; + NTSTATUS Status; + + DPRINT("MmUnmapViewInSystemSpace() called\n"); + + AddressSpace = MmGetKernelAddressSpace(); + + Status = MmUnmapViewOfSegment(AddressSpace, MappedBase); + + return Status; } +/* + * @unimplemented + */ NTSTATUS STDCALL MmSetBankedSection (DWORD Unknown0, DWORD Unknown1, @@ -3482,7 +3979,7 @@ MmSetBankedSection (DWORD Unknown0, * ARGUMENTS * SectionObjiect (OUT) * Caller supplied storage for the resulting pointer - * to a SECTION_BOJECT instance; + * to a SECTION_OBJECT instance; * * DesiredAccess * Specifies the desired access to the section can be a @@ -3524,6 +4021,8 @@ MmSetBankedSection (DWORD Unknown0, * * RETURN VALUE * Status. + * + * @unimplemented */ NTSTATUS STDCALL MmCreateSection (OUT PSECTION_OBJECT * SectionObject, @@ -3539,9 +4038,3 @@ MmCreateSection (OUT PSECTION_OBJECT * SectionObject, } /* EOF */ - - - - - -