Author: sir_richard
Date: Mon Oct 4 20:19:03 2010
New Revision: 48981
URL:
http://svn.reactos.org/svn/reactos?rev=48981&view=rev
Log:
[NTOS]: Implement MiMapViewInSystemSpace, all it took was another 250 lines and we can now
map ARM3 sections into memory. Accessing them causes a fault, which we correctly handle
with the prototype PTE fault code.
[NTOS]: Added a bogus allocation flag that can be used with Nt/MmCreateSection and
MmMapViewInSystemSpace to take the ARM3 path instead. Only for internal testing at the
moment.
Now we need to look at how to allow mapping these into user-space as well...
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/section.c
trunk/reactos/ntoskrnl/mm/section.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Mon Oct 4 20:19:03 2010
@@ -244,6 +244,11 @@
// Prototype PTEs that don't yet have a pagefile association
//
#define MI_PTE_LOOKUP_NEEDED 0xFFFFF
+
+//
+// System views are binned into 64K chunks
+//
+#define MI_SYSTEM_VIEW_BUCKET_SIZE 65536
//
// FIXFIX: These should go in ex.h after the pool merge
Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Mon Oct 4 20:19:03 2010
@@ -175,14 +175,14 @@
Session->SystemSpaceViewStart = MiSystemViewStart;
/* Create a bitmap to describe system space */
- BitmapSize = sizeof(RTL_BITMAP) + ((((MmSystemViewSize / 65536) + 31) / 32) *
sizeof(ULONG));
+ BitmapSize = sizeof(RTL_BITMAP) + ((((MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE)
+ 31) / 32) * sizeof(ULONG));
Session->SystemSpaceBitMap = ExAllocatePoolWithTag(NonPagedPool,
BitmapSize,
' mM');
ASSERT(Session->SystemSpaceBitMap);
RtlInitializeBitMap(Session->SystemSpaceBitMap,
(PULONG)(Session->SystemSpaceBitMap + 1),
- MmSystemViewSize / 65536);
+ MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE);
/* Set system space fully empty to begin with */
RtlClearAllBits(Session->SystemSpaceBitMap);
@@ -205,6 +205,262 @@
/* Success */
return TRUE;
+}
+
+PVOID
+NTAPI
+MiInsertInSystemSpace(IN PMMSESSION Session,
+ IN ULONG Buckets,
+ IN PCONTROL_AREA ControlArea)
+{
+ PVOID Base;
+ ULONG Entry, Hash, i;
+ PAGED_CODE();
+
+ /* Only global mappings supported for now */
+ ASSERT(Session == &MmSession);
+
+ /* Stay within 4GB and don't go past the number of hash entries available */
+ ASSERT(Buckets < MI_SYSTEM_VIEW_BUCKET_SIZE);
+ ASSERT(Session->SystemSpaceHashEntries < Session->SystemSpaceHashSize);
+
+ /* Find space where to map this view */
+ i = RtlFindClearBitsAndSet(Session->SystemSpaceBitMap, Buckets, 0);
+ ASSERT(i != 0xFFFFFFFF);
+ Base = (PVOID)((ULONG_PTR)Session->SystemSpaceViewStart + (i *
MI_SYSTEM_VIEW_BUCKET_SIZE));
+
+ /* Get the hash entry for this allocation */
+ Entry = ((ULONG_PTR)Base & ~(MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) + Buckets;
+ Hash = (Entry >> 16) % Session->SystemSpaceHashKey;
+
+ /* Loop hash entries until a free one is found */
+ while (Session->SystemSpaceViewTable[Hash].Entry)
+ {
+ /* Unless we overflow, in which case loop back at hash o */
+ if (++Hash >= Session->SystemSpaceHashSize) Hash = 0;
+ }
+
+ /* Add this entry into the hash table */
+ Session->SystemSpaceViewTable[Hash].Entry = Entry;
+ Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea;
+
+ /* Hash entry found, increment total and return the base address */
+ Session->SystemSpaceHashEntries++;
+ return Base;
+}
+
+NTSTATUS
+NTAPI
+MiAddMappedPtes(IN PMMPTE FirstPte,
+ IN PFN_NUMBER PteCount,
+ IN PCONTROL_AREA ControlArea)
+{
+ MMPTE TempPte;
+ PMMPTE PointerPte, ProtoPte, LastProtoPte, LastPte;
+ PSUBSECTION Subsection;
+
+ /* ARM3 doesn't support this yet */
+ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
+ ASSERT(ControlArea->u.Flags.Rom == 0);
+ ASSERT(ControlArea->FilePointer == NULL);
+
+ /* Sanity checks */
+ ASSERT(PteCount != 0);
+ ASSERT(ControlArea->NumberOfMappedViews >= 1);
+ ASSERT(ControlArea->NumberOfUserReferences >= 1);
+ ASSERT(ControlArea->NumberOfSectionReferences != 0);
+ ASSERT(ControlArea->u.Flags.BeingCreated == 0);
+ ASSERT(ControlArea->u.Flags.BeingDeleted == 0);
+ ASSERT(ControlArea->u.Flags.BeingPurged == 0);
+
+ /* Get the PTEs for the actual mapping */
+ PointerPte = FirstPte;
+ LastPte = FirstPte + PteCount;
+
+ /* Get the prototype PTEs that desribe the section mapping in the subsection */
+ Subsection = (PSUBSECTION)(ControlArea + 1);
+ ProtoPte = Subsection->SubsectionBase;
+ LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
+
+ /* Loop the PTEs for the mapping */
+ while (PointerPte < LastPte)
+ {
+ /* We may have run out of prototype PTEs in this subsection */
+ if (ProtoPte >= LastProtoPte)
+ {
+ /* But we don't handle this yet */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* The PTE should be completely clear */
+ ASSERT(PointerPte->u.Long == 0);
+
+ /* Build the prototype PTE and write it */
+ MI_MAKE_PROTOTYPE_PTE(&TempPte, ProtoPte);
+ MI_WRITE_INVALID_PTE(PointerPte, TempPte);
+
+ /* Keep going */
+ PointerPte++;
+ ProtoPte++;
+ }
+
+ /* No failure path */
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiFillSystemPageDirectory(IN PVOID Base,
+ IN SIZE_T NumberOfBytes)
+{
+ PMMPDE PointerPde, LastPde, SystemMapPde;
+ MMPDE TempPde;
+ PFN_NUMBER PageFrameIndex;
+ KIRQL OldIrql;
+ PAGED_CODE();
+
+ /* Find the PDEs needed for this mapping */
+ PointerPde = MiAddressToPde(Base);
+ LastPde = MiAddressToPde((PVOID)((ULONG_PTR)Base + NumberOfBytes - 1));
+
+ /* Find the system double-mapped PDE that describes this mapping */
+ SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE -
1)) / sizeof(MMPTE)];
+
+ /* Use the PDE template and loop the PDEs */
+ TempPde = ValidKernelPde;
+ while (PointerPde <= LastPde)
+ {
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Check if we don't already have this PDE mapped */
+ if (SystemMapPde->u.Hard.Valid == 0)
+ {
+ /* Grab a page for it */
+ PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
+ ASSERT(PageFrameIndex);
+ TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
+
+ /* Initialize its PFN entry, with the parent system page directory page table
*/
+ MiInitializePfnForOtherProcess(PageFrameIndex,
+ PointerPde,
+ MmSystemPageDirectory[(PointerPde -
MiAddressToPde(NULL)) / PDE_COUNT]);
+
+ /* Make the system PDE entry valid */
+ MI_WRITE_VALID_PTE(SystemMapPde, TempPde);
+
+ /* The system PDE entry might be the PDE itself, so check for this */
+ if (PointerPde->u.Hard.Valid == 0)
+ {
+ /* It's different, so make the real PDE valid too */
+ MI_WRITE_VALID_PTE(PointerPde, TempPde);
+ }
+ }
+
+ /* Release the lock and keep going with the next PDE */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ SystemMapPde++;
+ PointerPde++;
+ }
+}
+
+NTSTATUS
+NTAPI
+MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea,
+ IN BOOLEAN FailIfSystemViews)
+{
+ KIRQL OldIrql;
+
+ /* Flag not yet supported */
+ ASSERT(FailIfSystemViews == FALSE);
+
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* State not yet supported */
+ ASSERT(ControlArea->u.Flags.BeingPurged == 0);
+
+ /* Increase the reference counts */
+ ControlArea->NumberOfMappedViews++;
+ ControlArea->NumberOfUserReferences++;
+ ASSERT(ControlArea->NumberOfSectionReferences != 0);
+
+ /* Release the PFN lock and return success */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiMapViewInSystemSpace(IN PVOID Section,
+ IN PMMSESSION Session,
+ OUT PVOID *MappedBase,
+ IN OUT PSIZE_T ViewSize)
+{
+ PVOID Base;
+ PCONTROL_AREA ControlArea;
+ ULONG Buckets, SectionSize;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Only global mappings for now */
+ ASSERT(Session == &MmSession);
+
+ /* Get the control area, check for any flags ARM3 doesn't yet support */
+ ControlArea = ((PSECTION)Section)->Segment->ControlArea;
+ ASSERT(ControlArea->u.Flags.Image == 0);
+ ASSERT(ControlArea->FilePointer == NULL);
+ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
+ ASSERT(ControlArea->u.Flags.Rom == 0);
+ ASSERT(ControlArea->u.Flags.WasPurged == 0);
+
+ /* Increase the reference and map count on the control area, no purges yet */
+ Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Get the section size at creation time */
+ SectionSize = ((PSECTION)Section)->SizeOfSection.LowPart;
+
+ /* If the caller didn't specify a view size, assume the whole section */
+ if (!(*ViewSize)) *ViewSize = SectionSize;
+
+ /* Check if the caller wanted a larger section than the view */
+ if (*ViewSize > SectionSize)
+ {
+ /* We should probably fail. FIXME TODO */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Get the number of 64K buckets required for this mapping */
+ Buckets = *ViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE;
+ if (*ViewSize & (MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) Buckets++;
+
+ /* Check if the view is more than 4GB large */
+ if (Buckets >= MI_SYSTEM_VIEW_BUCKET_SIZE)
+ {
+ /* We should probably fail */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Insert this view into system space and get a base address for it */
+ Base = MiInsertInSystemSpace(Session, Buckets, ControlArea);
+ ASSERT(Base);
+
+ /* Create the PDEs needed for this mapping, and double-map them if needed */
+ MiFillSystemPageDirectory(Base, Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE);
+
+ /* Create the actual prototype PTEs for this mapping */
+ Status = MiAddMappedPtes(MiAddressToPte(Base),
+ BYTES_TO_PAGES(*ViewSize),
+ ControlArea);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Return the base adress of the mapping and success */
+ *MappedBase = Base;
+ return STATUS_SUCCESS;
}
NTSTATUS
Modified: trunk/reactos/ntoskrnl/mm/section.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/section.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/section.c [iso-8859-1] Mon Oct 4 20:19:03 2010
@@ -54,6 +54,23 @@
#pragma alloc_text(INIT, MmInitSectionImplementation)
#endif
+NTSTATUS
+NTAPI
+MiMapViewInSystemSpace(IN PVOID Section,
+IN PVOID Session,
+OUT PVOID *MappedBase,
+IN OUT PSIZE_T ViewSize);
+
+NTSTATUS
+NTAPI
+MmCreateArm3Section(OUT PVOID *SectionObject,
+IN ACCESS_MASK DesiredAccess,
+IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+IN PLARGE_INTEGER InputMaximumSize,
+IN ULONG SectionPageProtection,
+IN ULONG AllocationAttributes,
+IN HANDLE FileHandle OPTIONAL,
+IN PFILE_OBJECT FileObject OPTIONAL);
/* TYPES *********************************************************************/
@@ -4264,6 +4281,16 @@
PROS_SECTION_OBJECT Section;
PMMSUPPORT AddressSpace;
NTSTATUS Status;
+
+ if ((ULONG_PTR)SectionObject & 1)
+ {
+ PAGED_CODE();
+ extern PVOID MmSession;
+ return MiMapViewInSystemSpace((PVOID)((ULONG_PTR)SectionObject & ~1),
+ &MmSession,
+ MappedBase,
+ ViewSize);
+ }
DPRINT("MmMapViewInSystemSpace() called\n");
@@ -4386,6 +4413,20 @@
{
ULONG Protection;
PROS_SECTION_OBJECT *SectionObject = (PROS_SECTION_OBJECT *)Section;
+
+ /* Check if an ARM3 section is being created instead */
+ if (AllocationAttributes & 0xC0000000)
+ {
+ DPRINT1("arm 3 path\n");
+ return MmCreateArm3Section(Section,
+ DesiredAccess,
+ ObjectAttributes,
+ MaximumSize,
+ SectionPageProtection,
+ AllocationAttributes &~ 0xC0000000,
+ FileHandle,
+ File);
+ }
/*
* Check the protection