Two Part Patch which fixes ARM3 Section Support (not yet enabled). This had been enabled in the past for testing and resulted in bizare crashes during testing. The amount of fixing required should reveal why:

Part 1: Page Fault Path Fixes
[NTOS]: As an optimization, someone seems to have had changed the MiResolveDemandZeroFault prototype not to require a PTE, and to instead take a protection mask directly. While clever, this broke support for ARM3 sections, because the code was now assuming that the protection of the PTE for the input address should be used -- while in NT Sections we instead use what are called ProtoType PTEs. This was very annoying to debug, but since the cause has been fixed, I've reverted back to the old convention in which the PTE is passed-in, and this can be a different PTE than the PTE for the address, as it should be.
[NTOS]: Due to the reverting of the original path, another optimization, in which MiResolveDemandZeroFault was being called directly instead of going through MiDispatchFault and writing an invalid demand-zero PDE has also been removed. PDE faults are now going through the correct, expected path.
[NTOS]: MiResolveDemandZeroFault was always creating Kernel PTEs. It should create User PTEs when necessary.
[NTOS]: MiDeletePte was assuming any prototype PTE is a forked PTE. Forked PTEs only happen when the addresses in the PTE don't match, so check for that too.
Part 2: ARM3 Section Object Fixes
[NTOS]: Fix issue when trying to make both ROS_SECTION_OBJECTs and NT's SECTION co-exist. We relied on the *caller* knowing what kind of section this is, and that can't be a good idea. Now, when the caller requests an ARM3 section vs a ROS section, we use a marker to detect what kind of section this is for later APIs.
[NTOS]: For section VADs, we were storing the ReactOS MEMORY_AREA in the ControlArea... however, the mappings of one individual section object share a single control area, even though they have multiple MEMORY_AREAs (one for each mapping). As such, we overwrote the MEMORY_AREA continously, and at free-time, double or triple-freed the same memory area.
[NTOS]: Moved the MEMORY_AREA to the "Banked" field of the long VAD, instead of the ControlArea. Allocate MMVAD_LONGs for ARM3 sections for now, to support this. Also, after deleting the MEMORY_AREA while parsing VADs, we now use a special marker to detect double-frees, and we also use a special marker to make sure we have a Long VAD as expected.

svn path=/trunk/; revision=56035
This commit is contained in:
Sir Richard 2012-03-05 16:41:46 +00:00
parent 5219e590b0
commit d124bde10c
8 changed files with 152 additions and 64 deletions

View file

@ -298,7 +298,7 @@ ExpInitNls(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
NULL,
&SectionSize,
PAGE_READWRITE,
SEC_COMMIT,
SEC_COMMIT,// | 0x1,
NULL);
if (!NT_SUCCESS(Status))
{

View file

@ -1544,6 +1544,15 @@ MiRemoveZeroPageSafe(IN ULONG Color)
//
// New ARM3<->RosMM PAGE Architecture
//
BOOLEAN
FORCEINLINE
MiIsRosSectionObject(IN PVOID Section)
{
PROS_SECTION_OBJECT RosSection = Section;
if ((RosSection->Type == 'SC') && (RosSection->Size == 'TN')) return TRUE;
return FALSE;
}
#ifdef _WIN64
// HACK ON TOP OF HACK ALERT!!!
#define MI_GET_ROS_DATA(x) \

View file

@ -247,12 +247,11 @@ MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
NTSTATUS
NTAPI
MiResolveDemandZeroFault(IN PVOID Address,
IN ULONG Protection,
IN PMMPTE PointerPte,
IN PEPROCESS Process,
IN KIRQL OldIrql)
{
PFN_NUMBER PageFrameNumber = 0;
PMMPTE PointerPte = MiAddressToPte(Address);
MMPTE TempPte;
BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
ULONG Color;
@ -342,11 +341,23 @@ MiResolveDemandZeroFault(IN PVOID Address,
/* Zero the page if need be */
if (NeedZero) MiZeroPfn(PageFrameNumber);
/* Build the PTE */
MI_MAKE_HARDWARE_PTE(&TempPte,
PointerPte,
Protection,
PageFrameNumber);
/* Fault on user PDE, or fault on user PTE? */
if (PointerPte <= MiHighestUserPte)
{
/* User fault, build a user PTE */
MI_MAKE_HARDWARE_PTE_USER(&TempPte,
PointerPte,
PointerPte->u.Soft.Protection,
PageFrameNumber);
}
else
{
/* This is a user-mode PDE, create a kernel PTE for it */
MI_MAKE_HARDWARE_PTE(&TempPte,
PointerPte,
PointerPte->u.Soft.Protection,
PageFrameNumber);
}
/* Set it dirty if it's a writable page */
if (MI_IS_PAGE_WRITEABLE(&TempPte)) MI_MAKE_DIRTY_PAGE(&TempPte);
@ -494,7 +505,7 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
/* Resolve the demand zero fault */
Status = MiResolveDemandZeroFault(Address,
(ULONG)PointerProtoPte->u.Soft.Protection,
PointerProtoPte,
Process,
OldIrql);
ASSERT(NT_SUCCESS(Status));
@ -639,7 +650,7 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
// we want. Go handle it!
//
Status = MiResolveDemandZeroFault(Address,
(ULONG)PointerPte->u.Soft.Protection,
PointerPte,
Process,
MM_NOIRQL);
ASSERT(KeAreAllApcsDisabled() == TRUE);
@ -884,36 +895,40 @@ UserFault:
#endif
#if (_MI_PAGING_LEVELS == 4)
// Note to Timo: You should call MiCheckVirtualAddress and also check if it's zero pte
// also this is missing the page count increment
/* Check if the PXE is valid */
if (PointerPxe->u.Hard.Valid == 0)
{
/* Right now, we only handle scenarios where the PXE is totally empty */
ASSERT(PointerPxe->u.Long == 0);
#if 0
/* Resolve a demand zero fault */
Status = MiResolveDemandZeroFault(PointerPpe,
MM_READWRITE,
CurrentProcess,
MM_NOIRQL);
#endif
/* We should come back with a valid PXE */
ASSERT(PointerPxe->u.Hard.Valid == 1);
}
#endif
#if (_MI_PAGING_LEVELS >= 3)
// Note to Timo: You should call MiCheckVirtualAddress and also check if it's zero pte
// also this is missing the page count increment
/* Check if the PPE is valid */
if (PointerPpe->u.Hard.Valid == 0)
{
/* Right now, we only handle scenarios where the PPE is totally empty */
ASSERT(PointerPpe->u.Long == 0);
#if 0
/* Resolve a demand zero fault */
Status = MiResolveDemandZeroFault(PointerPde,
MM_READWRITE,
CurrentProcess,
MM_NOIRQL);
#endif
/* We should come back with a valid PPE */
ASSERT(PointerPpe->u.Hard.Valid == 1);
}
@ -929,11 +944,33 @@ UserFault:
#if MI_TRACE_PFNS
UserPdeFault = TRUE;
#endif
/* Resolve a demand zero fault */
Status = MiResolveDemandZeroFault(PointerPte,
MM_READWRITE,
CurrentProcess,
MM_NOIRQL);
MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
if (ProtectionCode == MM_NOACCESS)
{
#if (_MI_PAGING_LEVELS == 2)
/* Could be a page table for paged pool */
MiCheckPdeForPagedPool(Address);
#endif
/* Has the code above changed anything -- is this now a valid PTE? */
Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
/* Either this was a bogus VA or we've fixed up a paged pool PDE */
MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
return Status;
}
/* Write a demand-zero PDE */
MI_WRITE_INVALID_PTE(PointerPde, DemandZeroPde);
/* Dispatch the fault */
Status = MiDispatchFault(TRUE,
PointerPte,
PointerPde,
NULL,
FALSE,
PsGetCurrentProcess(),
TrapInformation,
NULL);
#if MI_TRACE_PFNS
UserPdeFault = FALSE;
#endif
@ -951,7 +988,7 @@ UserFault:
{
/* Resolve the fault */
MiResolveDemandZeroFault(Address,
(ULONG)PointerPte->u.Soft.Protection,
PointerPte,
CurrentProcess,
MM_NOIRQL);

View file

@ -694,7 +694,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
IN ULONG_PTR ZeroBits,
IN ULONG AllocationType)
{
PMMVAD Vad;
PMMVAD_LONG Vad;
PETHREAD Thread = PsGetCurrentThread();
ULONG_PTR StartAddress, EndingAddress;
PSUBSECTION Subsection;
@ -799,9 +799,11 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
/* A VAD can now be allocated. Do so and zero it out */
Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), 'ldaV');
/* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */
Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
ASSERT(Vad);
RtlZeroMemory(Vad, sizeof(MMVAD));
RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
Vad->u4.Banked = (PVOID)0xDEADBABE;
/* Write all the data required in the VAD for handling a fault */
Vad->StartingVpn = StartAddress >> PAGE_SHIFT;
@ -833,7 +835,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
MiLockProcessWorkingSet(Process, Thread);
/* Insert the VAD */
MiInsertVad(Vad, Process);
MiInsertVad((PMMVAD)Vad, Process);
/* Release the working set */
MiUnlockProcessWorkingSet(Process, Thread);
@ -844,6 +846,7 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
/* Finally, let the caller know where, and for what size, the view was mapped */
*ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1;
*BaseAddress = (PVOID)StartAddress;
DPRINT1("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize);
return STATUS_SUCCESS;
}
@ -961,10 +964,10 @@ MmGetFileObjectForSection(IN PVOID SectionObject)
ASSERT(SectionObject != NULL);
/* Check if it's an ARM3, or ReactOS section */
if ((ULONG_PTR)SectionObject & 1)
if (MiIsRosSectionObject(SectionObject) == FALSE)
{
/* Return the file pointer stored in the control area */
Section = (PVOID)((ULONG_PTR)SectionObject & ~1);
Section = SectionObject;
return Section->Segment->ControlArea->FilePointer;
}
@ -1012,10 +1015,10 @@ MmGetFileNameForSection(IN PVOID Section,
PFILE_OBJECT FileObject;
/* Make sure it's an image section */
if ((ULONG_PTR)Section & 1)
if (MiIsRosSectionObject(Section) == FALSE)
{
/* Check ARM3 Section flag */
if (((PSECTION)((ULONG_PTR)Section & ~1))->u.Flags.Image == 0)
if (((PSECTION)Section)->u.Flags.Image == 0)
{
/* It's not, fail */
DPRINT1("Not an image section\n");
@ -1323,6 +1326,9 @@ MmMapViewOfArm3Section(IN PVOID SectionObject,
NTSTATUS Status;
PAGED_CODE();
/* Force PAGE_READWRITE for everything, for now */
Protect = PAGE_READWRITE;
/* Get the segment and control area */
Section = (PSECTION)SectionObject;
ControlArea = Section->Segment->ControlArea;
@ -1334,7 +1340,6 @@ MmMapViewOfArm3Section(IN PVOID SectionObject,
ASSERT((AllocationType & MEM_RESERVE) == 0);
ASSERT(ControlArea->u.Flags.PhysicalMemory == 0);
#if 0
/* FIXME: Check if the mapping protection is compatible with the create */
if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect))
@ -1416,6 +1421,7 @@ MmMapViewOfArm3Section(IN PVOID SectionObject,
if (!Process->VmDeleted)
{
/* Do the actual mapping */
DPRINT1("Mapping ARM3 data section\n");
Status = MiMapViewOfDataSection(ControlArea,
Process,
BaseAddress,
@ -1498,11 +1504,11 @@ NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
PVOID AddressSpace;
PMEMORY_AREA MemoryArea1, MemoryArea2;
PROS_SECTION_OBJECT Section1, Section2;
/* Lock address space */
AddressSpace = MmGetCurrentAddressSpace();
MmLockAddressSpace(AddressSpace);
/* Locate the memory area for the process by address */
MemoryArea1 = MmLocateMemoryAreaByAddress(AddressSpace, File1MappedAsAnImage);
if (!MemoryArea1)
@ -1511,7 +1517,7 @@ NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
MmUnlockAddressSpace(AddressSpace);
return STATUS_INVALID_ADDRESS;
}
/* Check if it's a section view (RosMm section) or ARM3 section */
if (MemoryArea1->Type != MEMORY_AREA_SECTION_VIEW)
{
@ -1519,15 +1525,15 @@ NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
MmUnlockAddressSpace(AddressSpace);
return STATUS_CONFLICTING_ADDRESSES;
}
/* Get the section pointer to the SECTION_OBJECT */
Section1 = MemoryArea1->Data.SectionData.Section;
if (Section1->FileObject == NULL)
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_CONFLICTING_ADDRESSES;
return STATUS_CONFLICTING_ADDRESSES;
}
/* Locate the memory area for the process by address */
MemoryArea2 = MmLocateMemoryAreaByAddress(AddressSpace, File2MappedAsFile);
if (!MemoryArea2)
@ -1536,7 +1542,7 @@ NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
MmUnlockAddressSpace(AddressSpace);
return STATUS_INVALID_ADDRESS;
}
/* Check if it's a section view (RosMm section) or ARM3 section */
if (MemoryArea2->Type != MEMORY_AREA_SECTION_VIEW)
{
@ -1544,23 +1550,23 @@ NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
MmUnlockAddressSpace(AddressSpace);
return STATUS_CONFLICTING_ADDRESSES;
}
/* Get the section pointer to the SECTION_OBJECT */
Section2 = MemoryArea2->Data.SectionData.Section;
if (Section2->FileObject == NULL)
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_CONFLICTING_ADDRESSES;
return STATUS_CONFLICTING_ADDRESSES;
}
/* The shared cache map seems to be the same if both of these are equal */
if (Section1->FileObject->SectionObjectPointer->SharedCacheMap ==
Section2->FileObject->SectionObjectPointer->SharedCacheMap)
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_SUCCESS;
return STATUS_SUCCESS;
}
/* Unlock address space */
MmUnlockAddressSpace(AddressSpace);
return STATUS_NOT_SAME_DEVICE;

View file

@ -97,13 +97,13 @@ MiInsertNode(IN PMM_AVL_TABLE Table,
IN PMMADDRESS_NODE Parent,
IN TABLE_SEARCH_RESULT Result)
{
PMMVAD Vad;
PMMVAD_LONG Vad;
/* Insert it into the tree */
RtlpInsertAvlTreeNode(Table, NewNode, Parent, Result);
/* Now insert an ARM3 MEMORY_AREA for this node, unless the insert was already from the MEMORY_AREA code */
Vad = (PMMVAD)NewNode;
Vad = (PMMVAD_LONG)NewNode;
if (Vad->u.VadFlags.Spare == 0)
{
NTSTATUS Status;
@ -129,14 +129,13 @@ MiInsertNode(IN PMM_AVL_TABLE Table,
if (Vad->ControlArea == NULL)
{
/* We store the reactos MEMORY_AREA here */
DPRINT("Storing %p in %p\n", MemoryArea, Vad);
Vad->FirstPrototypePte = (PMMPTE)MemoryArea;
}
else
{
/* This is a section VAD. Store the MAREA here for now */
DPRINT("Storing %p in %p\n", MemoryArea, Vad);
Vad->ControlArea->WaitingForDeletion = (PVOID)MemoryArea;
ASSERT(Vad->u4.Banked = (PVOID)0xDEADBABE);
Vad->u4.Banked = (PVOID)MemoryArea;
}
}
}
@ -167,7 +166,7 @@ NTAPI
MiRemoveNode(IN PMMADDRESS_NODE Node,
IN PMM_AVL_TABLE Table)
{
PMMVAD Vad;
PMMVAD_LONG Vad;
/* Call the AVL code */
RtlpDeleteAvlTreeNode(Table, Node);
@ -184,7 +183,7 @@ MiRemoveNode(IN PMMADDRESS_NODE Node,
}
/* Free the node from ReactOS view as well */
Vad = (PMMVAD)Node;
Vad = (PMMVAD_LONG)Node;
if (Vad->u.VadFlags.Spare == 0)
{
PMEMORY_AREA MemoryArea;
@ -199,12 +198,15 @@ MiRemoveNode(IN PMMADDRESS_NODE Node,
else
{
/* This is a section VAD. We store the ReactOS MEMORY_AREA here */
MemoryArea = (PMEMORY_AREA)Vad->ControlArea->WaitingForDeletion;
MemoryArea = (PMEMORY_AREA)Vad->u4.Banked;
}
/* Make sure one actually still exists */
if (MemoryArea)
{
/* Make sure we have not already freed it */
ASSERT(MemoryArea != (PVOID)0xDEADBAB1);
/* Get the process */
Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot);
@ -214,6 +216,18 @@ MiRemoveNode(IN PMMADDRESS_NODE Node,
/* Free it */
MmFreeMemoryArea(&Process->Vm, MemoryArea, NULL, NULL);
/* Check if this is VM VAD */
if (Vad->ControlArea == NULL)
{
/* Delete the pointer to it */
Vad->FirstPrototypePte = (PVOID)0xDEADBAB1;
}
else
{
/* Delete the pointer to it */
Vad->u4.Banked = (PVOID)0xDEADBAB1;
}
}
}
}

View file

@ -258,7 +258,7 @@ MiDeletePte(IN PMMPTE PointerPte,
MiDecrementShareCount(Pfn1, PageFrameIndex);
/* Either a fork, or this is the shared user data page */
if (PointerPte <= MiHighestUserPte)
if ((PointerPte <= MiHighestUserPte) && (PrototypePte != Pfn1->PteAddress))
{
/* If it's not the shared user page, then crash, since there's no fork() yet */
if ((PAGE_ALIGN(VirtualAddress) != (PVOID)USER_SHARED_DATA) ||

View file

@ -222,11 +222,16 @@ MiSynchronizeSystemPde(PMMPDE PointerPde)
NTSTATUS
NTAPI
MiResolveDemandZeroFault(IN PVOID Address,
IN ULONG Protection,
IN PEPROCESS Process,
IN KIRQL OldIrql);
VOID
MiDispatchFault(IN BOOLEAN StoreInstruction,
IN PVOID Address,
IN PMMPTE PointerPte,
IN PMMPTE PointerProtoPte,
IN BOOLEAN Recursive,
IN PEPROCESS Process,
IN PVOID TrapInformation,
IN PVOID Vad);
NTSTATUS
NTAPI
MiFillSystemPageDirectory(IN PVOID Base,
IN SIZE_T NumberOfBytes);
@ -280,14 +285,23 @@ MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
Pt = (PULONG)MiAddressToPte(Address);
if (PointerPde->u.Hard.Valid == 0)
{
NTSTATUS Status;
if (Create == FALSE)
{
return NULL;
}
MiResolveDemandZeroFault(Pt,
MM_READWRITE,
Process,
MM_NOIRQL);
ASSERT(PointerPde->u.Long == 0);
MI_WRITE_INVALID_PTE(PointerPde, DemandZeroPde);
Status = MiDispatchFault(TRUE,
Pt,
PointerPde,
NULL,
FALSE,
PsGetCurrentProcess(),
NULL,
NULL);
ASSERT(KeAreAllApcsDisabled() == TRUE);
ASSERT(PointerPde->u.Hard.Valid == 1);
}
return (PULONG)MiAddressToPte(Address);

View file

@ -2917,6 +2917,8 @@ MmCreatePageFileSection(PROS_SECTION_OBJECT *SectionObject,
* Initialize it
*/
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
Section->Type = 'SC';
Section->Size = 'TN';
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
Section->MaximumSize = MaximumSize;
@ -2989,6 +2991,8 @@ MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
* Initialize it
*/
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
Section->Type = 'SC';
Section->Size = 'TN';
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
@ -3845,6 +3849,8 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
* Initialize it
*/
RtlZeroMemory(Section, sizeof(ROS_SECTION_OBJECT));
Section->Type = 'SC';
Section->Size = 'TN';
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
@ -4530,9 +4536,10 @@ MmMapViewOfSection(IN PVOID SectionObject,
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN NotAtBase = FALSE;
if ((ULONG_PTR)SectionObject & 1)
if (MiIsRosSectionObject(SectionObject) == FALSE)
{
return MmMapViewOfArm3Section((PVOID)((ULONG_PTR)SectionObject & ~1),
DPRINT1("Mapping ARM3 section into %s\n", Process->ImageFileName);
return MmMapViewOfArm3Section(SectionObject,
Process,
BaseAddress,
ZeroBits,
@ -4866,9 +4873,10 @@ MmMapViewInSystemSpace (IN PVOID SectionObject,
NTSTATUS Status;
PAGED_CODE();
if ((ULONG_PTR)SectionObject & 1)
if (MiIsRosSectionObject(SectionObject) == FALSE)
{
return MiMapViewInSystemSpace((PVOID)((ULONG_PTR)SectionObject & ~1),
DPRINT1("ARM3 System Mapping\n");
return MiMapViewInSystemSpace(SectionObject,
&MmSession,
MappedBase,
ViewSize);
@ -5004,7 +5012,7 @@ MmCreateSection (OUT PVOID * Section,
/* Check if an ARM3 section is being created instead */
if (AllocationAttributes & 1)
{
DPRINT1("arm 3 path\n");
DPRINT1("Creating ARM3 section\n");
return MmCreateArm3Section(Section,
DesiredAccess,
ObjectAttributes,