diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index b8995cfd5f3..eb1fa29c0fe 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -980,8 +980,51 @@ MiDispatchFault(IN BOOLEAN StoreInstruction, else if ((TempPte.u.Soft.Prototype == 0) && (TempPte.u.Soft.Transition == 1)) { - /* No standby support yet */ - ASSERT(FALSE); + /* This is a standby page, bring it back from the cache */ + PageFrameIndex = TempPte.u.Trans.PageFrameNumber; + DPRINT1("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex); + Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); + ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); + + /* Should not yet happen in ReactOS */ + ASSERT(Pfn1->u3.e1.ReadInProgress == 0); + ASSERT(Pfn1->u4.InPageError == 0); + + /* Get the page */ + MiUnlinkPageFromList(Pfn1); + + /* Bump its reference count */ + ASSERT(Pfn1->u2.ShareCount == 0); + InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); + Pfn1->u2.ShareCount++; + + /* Make it valid again */ + /* This looks like another macro.... */ + Pfn1->u3.e1.PageLocation = ActiveAndValid; + ASSERT(PointerProtoPte->u.Hard.Valid == 0); + ASSERT(PointerProtoPte->u.Trans.Prototype == 0); + ASSERT(PointerProtoPte->u.Trans.Transition == 1); + TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) | + MmProtectToPteMask[PointerProtoPte->u.Trans.Protection]; + TempPte.u.Hard.Valid = 1; + TempPte.u.Hard.Accessed = 1; + + /* Is the PTE writeable? */ + if (((Pfn1->u3.e1.Modified) && (TempPte.u.Hard.Write)) && + (TempPte.u.Hard.CopyOnWrite == 0)) + { + /* Make it dirty */ + TempPte.u.Hard.Dirty = TRUE; + } + else + { + /* Make it clean */ + TempPte.u.Hard.Dirty = FALSE; + } + + /* Write the valid PTE */ + MI_WRITE_VALID_PTE(PointerProtoPte, TempPte); + ASSERT(PointerPte->u.Hard.Valid == 0); } else { diff --git a/reactos/ntoskrnl/mm/ARM3/pfnlist.c b/reactos/ntoskrnl/mm/ARM3/pfnlist.c index cd633cb53cc..317f883f445 100644 --- a/reactos/ntoskrnl/mm/ARM3/pfnlist.c +++ b/reactos/ntoskrnl/mm/ARM3/pfnlist.c @@ -1335,7 +1335,6 @@ MiDecrementReferenceCount(IN PMMPFN Pfn1, } /* Check to see which list this page should go into */ - ASSERT(FALSE); if (Pfn1->u3.e1.Modified == 1) { /* Push it into the modified page list */ diff --git a/reactos/ntoskrnl/mm/ARM3/section.c b/reactos/ntoskrnl/mm/ARM3/section.c index f436639aaf2..c85ed25e303 100644 --- a/reactos/ntoskrnl/mm/ARM3/section.c +++ b/reactos/ntoskrnl/mm/ARM3/section.c @@ -894,10 +894,10 @@ MiSessionCommitPageTables(IN PVOID StartVa, ASSERT(ActualPages <= PageCount); /* Release the working set lock */ -// MiUnlockWorkingSet(PsGetCurrentThread(), +// MiUnlockWorkingSet(PsGetCurrentThread(), // &MmSessionSpace->GlobalVirtualAddress->Vm); - + /* If we did at least one page... */ if (ActualPages) { @@ -974,7 +974,7 @@ MiMapViewInSystemSpace(IN PVOID Section, { /* Create the PDEs needed for this mapping */ Status = MiSessionCommitPageTables(Base, - (PVOID)((ULONG_PTR)Base + + (PVOID)((ULONG_PTR)Base + Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE)); NT_ASSERT(NT_SUCCESS(Status)); } @@ -1243,6 +1243,37 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea, return STATUS_SUCCESS; } +VOID +NTAPI +MiSubsectionConsistent(IN PSUBSECTION Subsection) +{ + /* ReactOS only supports systems with 4K pages and 4K sectors */ + ASSERT(Subsection->u.SubsectionFlags.SectorEndOffset == 0); + + /* Therefore, then number of PTEs should be equal to the number of sectors */ + if (Subsection->NumberOfFullSectors != Subsection->PtesInSubsection) + { + /* Break and warn if this is inconsistent */ + DPRINT1("Mm: Subsection inconsistent (%x vs %x)\n", + Subsection->NumberOfFullSectors, Subsection->PtesInSubsection); + DbgBreakPoint(); + } +} + +NTSTATUS +NTAPI +MiCreateDataFileMap(IN PFILE_OBJECT File, + OUT PSEGMENT *Segment, + IN PSIZE_T MaximumSize, + IN ULONG SectionPageProtection, + IN ULONG AllocationAttributes, + IN ULONG IgnoreFileSizing) +{ + /* Not yet implemented */ + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + NTSTATUS NTAPI MiCreatePagingFileMap(OUT PSEGMENT *Segment, @@ -2048,15 +2079,15 @@ MmCreateArm3Section(OUT PVOID *SectionObject, SECTION Section; PSECTION NewSection; PSUBSECTION Subsection; - PSEGMENT NewSegment; + PSEGMENT NewSegment, Segment; NTSTATUS Status; PCONTROL_AREA ControlArea; - ULONG ProtectionMask; - - /* ARM3 does not yet support this */ - ASSERT(FileHandle == NULL); - ASSERT(FileObject == NULL); - ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); + ULONG ProtectionMask, ControlAreaSize, Size, NonPagedCharge, PagedCharge; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + BOOLEAN FileLock = FALSE, KernelCall = FALSE; + KIRQL OldIrql; + PFILE_OBJECT File; + PVOID PreviousSectionPointer; /* Make the same sanity checks that the Nt interface should've validated */ ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | @@ -2079,53 +2110,229 @@ MmCreateArm3Section(OUT PVOID *SectionObject, ProtectionMask = MiMakeProtectionMask(SectionPageProtection); if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION; - /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */ - if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; + /* Check if this is going to be a data or image backed file section */ + if ((FileHandle) || (FileObject)) + { + /* These cannot be mapped with large pages */ + if (AllocationAttributes & SEC_LARGE_PAGES) return STATUS_INVALID_PARAMETER_6; - /* So this must be a pagefile-backed section, create the mappings needed */ - Status = MiCreatePagingFileMap(&NewSegment, - (PSIZE_T)InputMaximumSize, - ProtectionMask, - AllocationAttributes); - ASSERT(NT_SUCCESS(Status)); - ASSERT(NewSegment != NULL); + /* For now, only support the mechanism through a file handle */ + ASSERT(FileObject == NULL); + + /* Reference the file handle to get the object */ + Status = ObReferenceObjectByHandle(FileHandle, + MmMakeFileAccess[ProtectionMask], + IoFileObjectType, + PreviousMode, + (PVOID*)&File, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Make sure Cc has been doing its job */ + if (!File->SectionObjectPointer) + { + /* This is not a valid file system-based file, fail */ + ObDereferenceObject(File); + return STATUS_INVALID_FILE_FOR_SECTION; + } + + /* Image-file backed sections are not yet supported */ + ASSERT((AllocationAttributes & SEC_IMAGE) == 0); + + /* Compute the size of the control area, and allocate it */ + ControlAreaSize = sizeof(CONTROL_AREA) + sizeof(MSUBSECTION); + ControlArea = ExAllocatePoolWithTag(NonPagedPool, ControlAreaSize, 'aCmM'); + if (!ControlArea) + { + ObDereferenceObject(File); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Zero it out */ + RtlZeroMemory(ControlArea, ControlAreaSize); + + /* Did we get a handle, or an object? */ + if (FileHandle) + { + /* We got a file handle so we have to lock down the file */ +#if 0 + Status = FsRtlAcquireToCreateMappedSection(File, SectionPageProtection); + if (!NT_SUCCESS(Status)) + { + ExFreePool(ControlArea); + ObDereferenceObject(File); + return Status; + } +#else + /* ReactOS doesn't support this API yet, so do nothing */ + Status = STATUS_SUCCESS; +#endif + /* Update the top-level IRP so that drivers know what's happening */ + IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); + FileLock = TRUE; + } + + /* Lock the PFN database while we play with the section pointers */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* Image-file backed sections are not yet supported */ + ASSERT((AllocationAttributes & SEC_IMAGE) == 0); + + /* There should not already be a control area for this file */ + ASSERT(File->SectionObjectPointer->DataSectionObject == NULL); + NewSegment = NULL; + + /* Write down that this CA is being created, and set it */ + ControlArea->u.Flags.BeingCreated = TRUE; + PreviousSectionPointer = File->SectionObjectPointer; + File->SectionObjectPointer->DataSectionObject = ControlArea; + + /* We can release the PFN lock now */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + /* We don't support previously-mapped file */ + ASSERT(NewSegment == NULL); + + /* Image-file backed sections are not yet supported */ + ASSERT((AllocationAttributes & SEC_IMAGE) == 0); + + /* So we always create a data file map */ + Status = MiCreateDataFileMap(File, + &Segment, + (PSIZE_T)InputMaximumSize, + SectionPageProtection, + AllocationAttributes, + KernelCall); + ASSERT(PreviousSectionPointer == File->SectionObjectPointer); + ASSERT(NT_SUCCESS(Status)); + + /* Check if a maximum size was specified */ + if (!InputMaximumSize->QuadPart) + { + /* Nope, use the segment size */ + Section.SizeOfSection.QuadPart = (LONGLONG)Segment->SizeOfSegment; + } + else + { + /* Yep, use the entered size */ + Section.SizeOfSection.QuadPart = InputMaximumSize->QuadPart; + } + + } + else + { + /* A handle must be supplied with SEC_IMAGE, as this is the no-handle path */ + if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; + + /* Not yet supported */ + ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); + + /* So this must be a pagefile-backed section, create the mappings needed */ + Status = MiCreatePagingFileMap(&NewSegment, + (PSIZE_T)InputMaximumSize, + ProtectionMask, + AllocationAttributes); + if (!NT_SUCCESS(Status)) return Status; + + /* Set the size here, and read the control area */ + Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment; + ControlArea = NewSegment->ControlArea; + } + + /* Did we already have a segment? */ + if (!NewSegment) + { + /* This must be the file path and we created a segment */ + NewSegment = Segment; + ASSERT(File != NULL); + + /* Acquire the PFN lock while we set control area flags */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* We don't support this race condition yet, so assume no waiters */ + ASSERT(ControlArea->WaitingForDeletion == NULL); + ControlArea->WaitingForDeletion = NULL; + + /* Image-file backed sections are not yet supported, nor ROM images */ + ASSERT((AllocationAttributes & SEC_IMAGE) == 0); + ASSERT(Segment->ControlArea->u.Flags.Rom == 0); + + /* Take off the being created flag, and then release the lock */ + ControlArea->u.Flags.BeingCreated = FALSE; + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + } + + /* Check if we locked the file earlier */ + if (FileLock) + { + /* Reset the top-level IRP and release the lock */ + IoSetTopLevelIrp(NULL); + //FsRtlReleaseFile(File); + FileLock = FALSE; + } /* Set the initial section object data */ Section.InitialPageProtection = SectionPageProtection; - Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment; - Section.Segment = NewSegment; - /* THe mapping created a control area and segment, save the flags */ - ControlArea = NewSegment->ControlArea; + /* The mapping created a control area and segment, save the flags */ + Section.Segment = NewSegment; Section.u.LongFlags = ControlArea->u.LongFlags; - /* ARM3 cannot support these right now, make sure they're not being set */ - ASSERT(ControlArea->u.Flags.Image == 0); - ASSERT(ControlArea->FilePointer == NULL); + /* Check if this is a user-mode read-write non-image file mapping */ + if (!(FileObject) && + (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) && + (ControlArea->u.Flags.Image == 0) && + (ControlArea->FilePointer != NULL)) + { + /* Add a reference and set the flag */ + Section.u.Flags.UserWritable = 1; + InterlockedIncrement((PLONG)&ControlArea->WritableUserReferences); + } + + /* Check for image mappings or page file mappings */ + if ((ControlArea->u.Flags.Image == 1) || !(ControlArea->FilePointer)) + { + /* Charge the segment size, and allocate a subsection */ + PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE); + Size = sizeof(SUBSECTION); + } + else + { + /* Charge nothing, and allocate a mapped subsection */ + PagedCharge = 0; + Size = sizeof(MSUBSECTION); + } + + /* Check if this is a normal CA */ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); ASSERT(ControlArea->u.Flags.Rom == 0); - ASSERT(ControlArea->u.Flags.WasPurged == 0); - /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */ + /* Charge only a CA, and the subsection is right after */ + NonPagedCharge = sizeof(CONTROL_AREA); Subsection = (PSUBSECTION)(ControlArea + 1); + + /* We only support single-subsection mappings */ + NonPagedCharge += Size; ASSERT(Subsection->NextSubsection == NULL); /* Create the actual section object, with enough space for the prototype PTEs */ - Status = ObCreateObject(ExGetPreviousMode(), + Status = ObCreateObject(PreviousMode, MmSectionObjectType, ObjectAttributes, - ExGetPreviousMode(), + PreviousMode, NULL, sizeof(SECTION), - sizeof(SECTION) + - NewSegment->TotalNumberOfPtes * sizeof(MMPTE), - sizeof(CONTROL_AREA) + sizeof(SUBSECTION), + PagedCharge, + NonPagedCharge, (PVOID*)&NewSection); ASSERT(NT_SUCCESS(Status)); /* Now copy the local section object from the stack into this new object */ RtlCopyMemory(NewSection, &Section, sizeof(SECTION)); NewSection->Address.StartingVpn = 0; + + /* For now, only user calls are supported */ + ASSERT(KernelCall == FALSE); NewSection->u.Flags.UserReference = TRUE; /* Migrate the attribute into a flag */ @@ -2171,6 +2378,13 @@ MmCreateArm3Section(OUT PVOID *SectionObject, KeReleaseGuardedMutex(&MmSectionBasedMutex); } + /* Write down if this was a kernel call */ + ControlArea->u.Flags.WasPurged |= KernelCall; + ASSERT(ControlArea->u.Flags.WasPurged == FALSE); + + /* Make sure the segment and the section are the same size, or the section is smaller */ + ASSERT(NewSection->SizeOfSection.QuadPart <= NewSection->Segment->SizeOfSegment); + /* Return the object and the creation status */ *SectionObject = (PVOID)NewSection; return Status; diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index 802f767c881..4f0d75f5ebe 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -4860,17 +4860,19 @@ MmCreateSection (OUT PVOID * Section, PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section; /* Check if an ARM3 section is being created instead */ - if (AllocationAttributes & 1) + if (!(AllocationAttributes & SEC_IMAGE) && (AllocationAttributes)) { - DPRINT1("Creating ARM3 section\n"); - return MmCreateArm3Section(Section, - DesiredAccess, - ObjectAttributes, - MaximumSize, - SectionPageProtection, - AllocationAttributes &~ 1, - FileHandle, - FileObject); + if (!(FileObject) && !(FileHandle)) + { + return MmCreateArm3Section(Section, + DesiredAccess, + ObjectAttributes, + MaximumSize, + SectionPageProtection, + AllocationAttributes &~ 1, + FileHandle, + FileObject); + } } /*