Sync with trunk (48237)
[reactos.git] / ntoskrnl / mm / ARM3 / procsup.c
index 4410624..857a181 100644 (file)
 
 extern MM_SYSTEMSIZE MmSystemSize;
 
-PVOID
+/* PRIVATE FUNCTIONS **********************************************************/
+
+VOID
 NTAPI
-MiCreatePebOrTeb(PEPROCESS Process,
-                 PVOID BaseAddress);
+MiRosTakeOverPebTebRanges(IN PEPROCESS Process)
+{
+    NTSTATUS Status;
+    PMEMORY_AREA MemoryArea;
+    PHYSICAL_ADDRESS BoundaryAddressMultiple;
+    PVOID AllocatedBase = (PVOID)MI_LOWEST_VAD_ADDRESS;
+    BoundaryAddressMultiple.QuadPart = 0;
 
-/* PRIVATE FUNCTIONS **********************************************************/
+    Status = MmCreateMemoryArea(&Process->Vm,
+                                MEMORY_AREA_OWNED_BY_ARM3,
+                                &AllocatedBase,
+                                ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - 1) -
+                                (ULONG_PTR)MI_LOWEST_VAD_ADDRESS,
+                                PAGE_READWRITE,
+                                &MemoryArea,
+                                TRUE,
+                                0,
+                                BoundaryAddressMultiple);
+    ASSERT(NT_SUCCESS(Status));
+}
+
+NTSTATUS
+NTAPI
+MiCreatePebOrTeb(IN PEPROCESS Process,
+                 IN ULONG Size,
+                 OUT PULONG_PTR Base)
+{
+    PETHREAD Thread = PsGetCurrentThread();
+    PMMVAD_LONG Vad;
+    NTSTATUS Status;
+    ULONG RandomCoeff;
+    ULONG_PTR StartAddress, EndAddress;
+    LARGE_INTEGER CurrentTime;
+    
+    /* Allocate a VAD */
+    Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
+    if (!Vad) return STATUS_NO_MEMORY;
+    
+    /* Setup the primary flags with the size, and make it commited, private, RW */
+    Vad->u.LongFlags = 0;
+    Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size);
+    Vad->u.VadFlags.MemCommit = TRUE;
+    Vad->u.VadFlags.PrivateMemory = TRUE;
+    Vad->u.VadFlags.Protection = MM_READWRITE;
+    Vad->u.VadFlags.NoChange = TRUE;
+    
+    /* Setup the secondary flags to make it a secured, writable, long VAD */
+    Vad->u2.LongFlags2 = 0;
+    Vad->u2.VadFlags2.OneSecured = TRUE;
+    Vad->u2.VadFlags2.LongVad = TRUE;
+    Vad->u2.VadFlags2.ReadOnly = FALSE;
+    
+    /* Lock the process address space */
+    KeAcquireGuardedMutex(&Process->AddressCreationLock);
+
+    /* Check if this is a PEB creation */
+    if (Size == sizeof(PEB))
+    {
+        /* Start at the highest valid address */
+        StartAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
+
+        /* Select the random coefficient */
+        KeQueryTickCount(&CurrentTime);
+        CurrentTime.LowPart &= ((64 * _1KB) >> PAGE_SHIFT) - 1;
+        if (CurrentTime.LowPart <= 1) CurrentTime.LowPart = 2;
+        RandomCoeff = CurrentTime.LowPart << PAGE_SHIFT;
+
+        /* Select the highest valid address minus the random coefficient */
+        StartAddress -= RandomCoeff;
+        EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
+
+        /* See if this VA range can be obtained */
+        if (!MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
+                                       EndAddress >> PAGE_SHIFT,
+                                       &Process->VadRoot))
+        {
+            /* No conflict, use this address */
+            *Base = StartAddress;
+            goto AfterFound;
+        }
+    }
+    
+    /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
+    Status = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
+                                             (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
+                                             PAGE_SIZE,
+                                             &Process->VadRoot,
+                                             Base);
+    ASSERT(NT_SUCCESS(Status));
+    
+AfterFound:
+    /* Validate that it came from the VAD ranges */
+    ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
+    
+    /* Build the rest of the VAD now */
+    Vad->StartingVpn = (*Base) >> PAGE_SHIFT;
+    Vad->EndingVpn =  ((*Base) + Size - 1) >> PAGE_SHIFT;
+    Vad->u3.Secured.StartVpn = *Base;
+    Vad->u3.Secured.EndVpn = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
+    
+    /* FIXME: Should setup VAD bitmap */
+    Status = STATUS_SUCCESS;
+
+    /* Pretend as if we own the working set */
+    MiLockProcessWorkingSet(Process, Thread);
+    
+    /* Insert the VAD */
+    ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
+    Process->VadRoot.NodeHint = Vad;
+    MiInsertNode((PVOID)Vad, &Process->VadRoot);
+    
+    /* Release the working set */
+    MiUnlockProcessWorkingSet(Process, Thread);
+
+    /* Release the address space lock */
+    KeReleaseGuardedMutex(&Process->AddressCreationLock);
+
+    /* Return the status */
+    DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
+    return Status;
+}
+
+VOID
+NTAPI
+MmDeleteTeb(IN PEPROCESS Process,
+            IN PTEB Teb)
+{
+    ULONG_PTR TebEnd;
+    PETHREAD Thread = PsGetCurrentThread();
+    PMMVAD Vad;
+    PMM_AVL_TABLE VadTree = &Process->VadRoot;
+    DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName);
+    
+    /* TEB is one page */
+    TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1;
+    
+    /* Attach to the process */
+    KeAttachProcess(&Process->Pcb);
+    
+    /* Lock the process address space */
+    KeAcquireGuardedMutex(&Process->AddressCreationLock);
+    
+    /* Find the VAD, make sure it's a TEB VAD */
+    Vad = MiLocateAddress(Teb);
+    DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
+    ASSERT(Vad != NULL);    
+    if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT))
+    {
+        /* Bug in the AVL code? */
+        DPRINT1("Corrupted VAD!\n");
+    }
+    else
+    {
+        /* Sanity checks for a valid TEB VAD */
+        ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) &&
+               (Vad->EndingVpn == (TebEnd >> PAGE_SHIFT))));
+        ASSERT(Vad->u.VadFlags.NoChange == TRUE);
+        ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
+
+        /* Lock the working set */
+        MiLockProcessWorkingSet(Process, Thread);
+
+        /* Remove this VAD from the tree */
+        ASSERT(VadTree->NumberGenericTableElements >= 1);
+        MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
+    
+        /* Release the working set */
+        MiUnlockProcessWorkingSet(Process, Thread);
+    
+        /* Remove the VAD */
+        ExFreePool(Vad);
+    }
+
+    /* Release the address space lock */
+    KeReleaseGuardedMutex(&Process->AddressCreationLock);
+    
+    /* Detach */
+    KeDetachProcess();
+}
 
 VOID
 NTAPI
@@ -156,7 +333,7 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
     MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
 
     /* Setup the template stack PTE */
-    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte + 1, MM_READWRITE, 0);
+    MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
     
     //
     // Acquire the PFN DB lock
@@ -270,7 +447,7 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
         MiInitializePfn(PageFrameIndex, LimitPte, 1);
         
         /* Setup the template stack PTE */
-        MI_MAKE_HARDWARE_PTE(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
+        MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
         
         /* Write the valid PTE */
         MI_WRITE_VALID_PTE(LimitPte--, TempPte);
@@ -392,10 +569,9 @@ MmCreatePeb(IN PEPROCESS Process,
     //
     // Allocate the PEB
     //
-    Peb = MiCreatePebOrTeb(Process,
-                           (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
-    ASSERT(Peb == (PVOID)0x7FFDF000);
-    
+    Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
+    ASSERT(NT_SUCCESS(Status));
+
     //
     // Map NLS Tables
     //
@@ -628,9 +804,8 @@ MmCreateTeb(IN PEPROCESS Process,
     //
     // Allocate the TEB
     //
-    Teb = MiCreatePebOrTeb(Process,
-                           (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
-    if (!Teb) return STATUS_INSUFFICIENT_RESOURCES;
+    Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
+    ASSERT(NT_SUCCESS(Status));
     
     //
     // Use SEH in case we can't load the TEB
@@ -706,6 +881,308 @@ MmCreateTeb(IN PEPROCESS Process,
     return Status;
 }
 
+NTSTATUS
+NTAPI
+MmInitializeProcessAddressSpace(IN PEPROCESS Process,
+                                IN PEPROCESS ProcessClone OPTIONAL,
+                                IN PVOID Section OPTIONAL,
+                                IN OUT PULONG Flags,
+                                IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    SIZE_T ViewSize = 0;
+    PVOID ImageBase = 0;
+    PROS_SECTION_OBJECT SectionObject = Section;
+    PMMPTE PointerPte;
+    KIRQL OldIrql;
+    PMMPDE PointerPde;
+    PFN_NUMBER PageFrameNumber;
+    UNICODE_STRING FileName;
+    PWCHAR Source;
+    PCHAR Destination;
+    USHORT Length = 0;
+    
+    /* We should have a PDE */
+    ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
+    ASSERT(Process->PdeUpdateNeeded == FALSE);
+
+    /* Attach to the process */
+    KeAttachProcess(&Process->Pcb);
+    
+    /* The address space should now been in phase 1 or 0 */
+    ASSERT(Process->AddressSpaceInitialized <= 1);
+    Process->AddressSpaceInitialized = 2;
+
+    /* Initialize the Addresss Space lock */
+    KeInitializeGuardedMutex(&Process->AddressCreationLock);
+    Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
+
+    /* Initialize AVL tree */
+    ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
+    Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
+
+    /* Lock PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Setup the PFN for the PDE base of this process */
+    PointerPte = MiAddressToPte(PDE_BASE);
+    PageFrameNumber = PFN_FROM_PTE(PointerPte);
+    MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
+
+    /* Do the same for hyperspace */
+    PointerPde = MiAddressToPde(HYPER_SPACE);
+    PageFrameNumber = PFN_FROM_PTE(PointerPde);
+    MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
+
+    /* Release PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+    /* Lock the VAD, ARM3-owned ranges away */
+    MiRosTakeOverPebTebRanges(Process);
+
+    /* Check if there's a Section Object */
+    if (SectionObject)
+    {
+        /* Determine the image file name and save it to EPROCESS */
+        FileName = SectionObject->FileObject->FileName;
+        Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
+        if (FileName.Buffer)
+        {
+            /* Loop the file name*/
+            while (Source > FileName.Buffer)
+            {
+                /* Make sure this isn't a backslash */
+                if (*--Source == OBJ_NAME_PATH_SEPARATOR)
+                {
+                    /* If so, stop it here */
+                    Source++;
+                    break;
+                }
+                else
+                {
+                    /* Otherwise, keep going */
+                    Length++;
+                }
+            }
+        }
+
+        /* Copy the to the process and truncate it to 15 characters if necessary */
+        Destination = Process->ImageFileName;
+        Length = min(Length, sizeof(Process->ImageFileName) - 1);
+        while (Length--) *Destination++ = (UCHAR)*Source++;
+        *Destination = ANSI_NULL;
+
+        /* Check if caller wants an audit name */
+        if (AuditName)
+        {
+            /* Setup the audit name */
+            Status = SeInitializeProcessAuditName(SectionObject->FileObject,
+                                                  FALSE,
+                                                  AuditName);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Fail */
+                KeDetachProcess();
+                return Status;
+            }
+        }
+
+        /* Map the section */
+        Status = MmMapViewOfSection(Section,
+                                    Process,
+                                    (PVOID*)&ImageBase,
+                                    0,
+                                    0,
+                                    NULL,
+                                    &ViewSize,
+                                    0,
+                                    MEM_COMMIT,
+                                    PAGE_READWRITE);
+
+        /* Save the pointer */
+        Process->SectionBaseAddress = ImageBase;
+    }
+    
+    /* Be nice and detach */
+    KeDetachProcess();
+
+    /* Return status to caller */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MmInitializeHandBuiltProcess(IN PEPROCESS Process,
+                             IN PULONG_PTR DirectoryTableBase)
+{
+    /* Share the directory base with the idle process */
+    DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
+    DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
+
+    /* Initialize the Addresss Space */
+    KeInitializeGuardedMutex(&Process->AddressCreationLock);
+    KeInitializeSpinLock(&Process->HyperSpaceLock);
+    Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
+    ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
+    Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
+
+    /* Done */
+    Process->HasAddressSpace = TRUE;//??
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
+{
+    /* Lock the VAD, ARM3-owned ranges away */                            
+    MiRosTakeOverPebTebRanges(Process);
+    return STATUS_SUCCESS;
+}
+
+/* FIXME: Evaluate ways to make this portable yet arch-specific */
+BOOLEAN
+NTAPI
+MmCreateProcessAddressSpace(IN ULONG MinWs,
+                            IN PEPROCESS Process,
+                            OUT PULONG_PTR DirectoryTableBase)
+{
+    KIRQL OldIrql;
+    PFN_NUMBER PdeIndex, HyperIndex;
+    PMMPTE PointerPte;
+    MMPTE TempPte, PdePte;
+    ULONG PdeOffset;
+    PMMPTE SystemTable;
+
+    /* No page colors yet */
+    Process->NextPageColor = 0;
+    
+    /* Setup the hyperspace lock */
+    KeInitializeSpinLock(&Process->HyperSpaceLock);
+
+    /* Lock PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    
+    /* Get a page for the PDE */
+    PdeIndex = MiRemoveAnyPage(0);
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    MiZeroPhysicalPage(PdeIndex);
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Get a page for hyperspace */
+    HyperIndex = MiRemoveAnyPage(0);
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+    MiZeroPhysicalPage(HyperIndex);
+
+    /* Switch to phase 1 initialization */
+    ASSERT(Process->AddressSpaceInitialized == 0);
+    Process->AddressSpaceInitialized = 1;
+
+    /* Set the base directory pointers */
+    DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
+    DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
+
+    /* Make sure we don't already have a page directory setup */
+    ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
+
+    /* Insert us into the Mm process list */
+    InsertTailList(&MmProcessList, &Process->MmProcessLinks);
+
+    /* Get a PTE to map the page directory */
+    PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
+    ASSERT(PointerPte != NULL);
+
+    /* Build it */
+    MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
+                                PointerPte,
+                                MM_READWRITE,
+                                PdeIndex);
+
+    /* Set it dirty and map it */
+    PdePte.u.Hard.Dirty = TRUE;
+    MI_WRITE_VALID_PTE(PointerPte, PdePte);
+
+    /* Now get the page directory (which we'll double map, so call it a page table */
+    SystemTable = MiPteToAddress(PointerPte);
+
+    /* Copy all the kernel mappings */
+    PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
+
+    RtlCopyMemory(&SystemTable[PdeOffset],
+                  MiAddressToPde(MmSystemRangeStart),
+                  PAGE_SIZE - PdeOffset * sizeof(MMPTE));
+
+    /* Now write the PTE/PDE entry for hyperspace itself */
+    TempPte = ValidKernelPte;
+    TempPte.u.Hard.PageFrameNumber = HyperIndex;
+    PdeOffset = MiGetPdeOffset(HYPER_SPACE);
+    SystemTable[PdeOffset] = TempPte;
+
+    /* Sanity check */
+    PdeOffset++;
+    ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
+
+    /* Now do the x86 trick of making the PDE a page table itself */
+    PdeOffset = MiGetPdeOffset(PTE_BASE);
+    TempPte.u.Hard.PageFrameNumber = PdeIndex;
+    SystemTable[PdeOffset] = TempPte;
+
+    /* Let go of the system PTE */
+    MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
+    return TRUE;
+}
+
+VOID
+NTAPI
+MmCleanProcessAddressSpace(IN PEPROCESS Process)
+{
+    PMMVAD Vad;
+    PMM_AVL_TABLE VadTree;
+    PETHREAD Thread = PsGetCurrentThread();
+    
+    /* Lock the process address space from changes */
+    MmLockAddressSpace(&Process->Vm);
+    
+    /* Enumerate the VADs */
+    VadTree = &Process->VadRoot;
+    DPRINT("Cleaning up VADs: %d\n", VadTree->NumberGenericTableElements);
+    while (VadTree->NumberGenericTableElements)
+    {
+        /* Grab the current VAD */
+        Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
+
+        /* Lock the working set */
+        MiLockProcessWorkingSet(Process, Thread);
+
+        /* Remove this VAD from the tree */
+        ASSERT(VadTree->NumberGenericTableElements >= 1);
+        DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
+        MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
+        DPRINT("Moving on: %d\n", VadTree->NumberGenericTableElements);
+
+        /* Check if this VAD was the hint */
+        if (VadTree->NodeHint == Vad)
+        {
+            /* Get a new hint, unless we're empty now, in which case nothing */
+            VadTree->NodeHint = VadTree->BalancedRoot.RightChild;
+            if (!VadTree->NumberGenericTableElements) VadTree->NodeHint = NULL;
+        }
+        
+        /* Only PEB/TEB VADs supported for now */
+        ASSERT(Vad->u.VadFlags.PrivateMemory == 1);
+        ASSERT(Vad->u.VadFlags.VadType == VadNone);
+        
+        /* Release the working set */
+        MiUnlockProcessWorkingSet(Process, Thread);
+        
+        /* Free the VAD memory */
+        ExFreePool(Vad);
+    }
+    
+    /* Release the address space */
+    MmUnlockAddressSpace(&Process->Vm);
+}
+
 /* SYSTEM CALLS ***************************************************************/
 
 NTSTATUS