[NTOSKRNL]: Cleanup MmCreateArm3Section a little bit to handle file-backed sections in the future.

[NTOSKRNL]: Remove an ASSERT(FALSE) that was only there for testing.
[NTOSKRNL]: Support transition pages during prototype PTE faults, which is our first try at soft faults! Should fix ASSERTs that were seen in the previous attempts in ole32, corrupting the registry.
[NTOSKRNL]: It's fine for MiCreatePagingFileMap to fail in MmCreateSection -- don't assert and simply return failure. Should fix the ASSERTs taht were seen in KmTest.
[NTOSKRNL]: Enable richard's ARM3 section code unconditionally for all non-file backed sections. Works4me. Let's see what Testbot says.
Nobody has showed me how to use/where is PatchBot, and google founds 0 relevant results, so this is going into main again. However I'm actually home this week to revert if something goes wrong :)


svn path=/trunk/; revision=57209
This commit is contained in:
Alex Ionescu 2012-09-01 02:32:25 +00:00
parent 5666d93992
commit cda03c0940
4 changed files with 304 additions and 46 deletions

View File

@ -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
{

View File

@ -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 */

View File

@ -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;

View File

@ -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);
}
}
/*