[NTOSKRNL]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Tue, 19 Nov 2013 21:13:31 +0000 (21:13 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Tue, 19 Nov 2013 21:13:31 +0000 (21:13 +0000)
Move session routines into session.c. No code change.

svn path=/trunk/; revision=61050

reactos/ntoskrnl/CMakeLists.txt
reactos/ntoskrnl/mm/ARM3/procsup.c
reactos/ntoskrnl/mm/ARM3/session.c [new file with mode: 0644]

index 0eb37fb..793e44d 100644 (file)
@@ -216,6 +216,7 @@ list(APPEND SOURCE
     mm/ARM3/pool.c
     mm/ARM3/procsup.c
     mm/ARM3/section.c
+    mm/ARM3/session.c
     mm/ARM3/special.c
     mm/ARM3/sysldr.c
     mm/ARM3/syspte.c
index 982fc5b..8bb17d0 100644 (file)
@@ -556,41 +556,6 @@ MmSetMemoryPriorityProcess(IN PEPROCESS Process,
     return OldPriority;
 }
 
-LCID
-NTAPI
-MmGetSessionLocaleId(VOID)
-{
-    PEPROCESS Process;
-    PAGED_CODE();
-
-    //
-    // Get the current process
-    //
-    Process = PsGetCurrentProcess();
-
-    //
-    // Check if it's the Session Leader
-    //
-    if (Process->Vm.Flags.SessionLeader)
-    {
-        //
-        // Make sure it has a valid Session
-        //
-        if (Process->Session)
-        {
-            //
-            // Get the Locale ID
-            //
-            return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
-        }
-    }
-
-    //
-    // Not a session leader, return the default
-    //
-    return PsDefaultThreadLocaleId;
-}
-
 NTSTATUS
 NTAPI
 MmCreatePeb(IN PEPROCESS Process,
@@ -1473,653 +1438,6 @@ MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
     Process->Pcb.DirectoryTableBase[1] = 0;
 }
 
-/* SESSION CODE TO MOVE TO SESSION.C ******************************************/
-
-PMM_SESSION_SPACE MmSessionSpace;
-PFN_NUMBER MiSessionDataPages, MiSessionTagPages, MiSessionTagSizePages;
-PFN_NUMBER MiSessionBigPoolPages, MiSessionCreateCharge;
-KGUARDED_MUTEX MiSessionIdMutex;
-LONG MmSessionDataPages;
-PRTL_BITMAP MiSessionIdBitmap;
-volatile LONG MiSessionLeaderExists;
-
-VOID
-NTAPI
-MiInitializeSessionIds(VOID)
-{
-    ULONG Size, BitmapSize;
-    PFN_NUMBER TotalPages;
-
-    /* Setup the total number of data pages needed for the structure */
-    TotalPages = MI_SESSION_DATA_PAGES_MAXIMUM;
-    MiSessionDataPages = ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE)) >> PAGE_SHIFT;
-    ASSERT(MiSessionDataPages <= MI_SESSION_DATA_PAGES_MAXIMUM - 3);
-    TotalPages -= MiSessionDataPages;
-
-    /* Setup the number of pages needed for session pool tags */
-    MiSessionTagSizePages = 2;
-    MiSessionBigPoolPages = 1;
-    MiSessionTagPages = MiSessionTagSizePages + MiSessionBigPoolPages;
-    ASSERT(MiSessionTagPages <= TotalPages);
-    ASSERT(MiSessionTagPages < MI_SESSION_TAG_PAGES_MAXIMUM);
-
-    /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
-    MiSessionCreateCharge = 1 + MiSessionDataPages + MiSessionTagPages;
-
-    /* Initialize the lock */
-    KeInitializeGuardedMutex(&MiSessionIdMutex);
-
-    /* Allocate the bitmap */
-    Size = MI_INITIAL_SESSION_IDS;
-    BitmapSize = ((Size + 31) / 32) * sizeof(ULONG);
-    MiSessionIdBitmap = ExAllocatePoolWithTag(PagedPool,
-                                              sizeof(RTL_BITMAP) + BitmapSize,
-                                              '  mM');
-    if (MiSessionIdBitmap)
-    {
-        /* Free all the bits */
-        RtlInitializeBitMap(MiSessionIdBitmap,
-                            (PVOID)(MiSessionIdBitmap + 1),
-                            Size);
-        RtlClearAllBits(MiSessionIdBitmap);
-    }
-    else
-    {
-        /* Die if we couldn't allocate the bitmap */
-        KeBugCheckEx(INSTALL_MORE_MEMORY,
-                     MmNumberOfPhysicalPages,
-                     MmLowestPhysicalPage,
-                     MmHighestPhysicalPage,
-                     0x200);
-    }
-}
-
-VOID
-NTAPI
-MiSessionLeader(IN PEPROCESS Process)
-{
-    KIRQL OldIrql;
-
-    /* Set the flag while under the expansion lock */
-    OldIrql = KeAcquireQueuedSpinLock(LockQueueExpansionLock);
-    Process->Vm.Flags.SessionLeader = TRUE;
-    KeReleaseQueuedSpinLock(LockQueueExpansionLock, OldIrql);
-}
-
-ULONG
-NTAPI
-MmGetSessionId(IN PEPROCESS Process)
-{
-    PMM_SESSION_SPACE SessionGlobal;
-
-    /* The session leader is always session zero */
-    if (Process->Vm.Flags.SessionLeader == 1) return 0;
-
-    /* Otherwise, get the session global, and read the session ID from it */
-    SessionGlobal = (PMM_SESSION_SPACE)Process->Session;
-    if (!SessionGlobal) return 0;
-    return SessionGlobal->SessionId;
-}
-
-ULONG
-NTAPI
-MmGetSessionIdEx(IN PEPROCESS Process)
-{
-    PMM_SESSION_SPACE SessionGlobal;
-
-    /* The session leader is always session zero */
-    if (Process->Vm.Flags.SessionLeader == 1) return 0;
-
-    /* Otherwise, get the session global, and read the session ID from it */
-    SessionGlobal = (PMM_SESSION_SPACE)Process->Session;
-    if (!SessionGlobal) return -1;
-    return SessionGlobal->SessionId;
-}
-
-VOID
-NTAPI
-MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal)
-{
-    ULONG i, SessionId;
-    PMMPTE PointerPte;
-    PFN_NUMBER PageFrameIndex[MI_SESSION_DATA_PAGES_MAXIMUM];
-    PMMPFN Pfn1;
-    KIRQL OldIrql;
-
-    /* Is there more than just this reference? If so, bail out */
-    if (InterlockedDecrement(&SessionGlobal->ProcessReferenceToSession)) return;
-
-    /* Get the session ID */
-    SessionId = SessionGlobal->SessionId;
-    DPRINT1("Last process in session %lu going down!!!\n", SessionId);
-
-    /* Free the session page tables */
-#ifndef _M_AMD64
-    ExFreePoolWithTag(SessionGlobal->PageTables, 'tHmM');
-#endif
-    ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal));
-
-    /* Capture the data page PFNs */
-    PointerPte = MiAddressToPte(SessionGlobal);
-    for (i = 0; i < MiSessionDataPages; i++)
-    {
-        PageFrameIndex[i] = PFN_FROM_PTE(PointerPte + i);
-    }
-
-    /* Release them */
-    MiReleaseSystemPtes(PointerPte, MiSessionDataPages, SystemPteSpace);
-
-    /* Mark them as deleted */
-    for (i = 0; i < MiSessionDataPages; i++)
-    {
-        Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
-        MI_SET_PFN_DELETED(Pfn1);
-    }
-
-    /* Loop every data page and drop a reference count */
-    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    for (i = 0; i < MiSessionDataPages; i++)
-    {
-        /* Sanity check that the page is correct, then decrement it */
-        Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
-        ASSERT(Pfn1->u2.ShareCount == 1);
-        ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
-        MiDecrementShareCount(Pfn1, PageFrameIndex[i]);
-    }
-
-    /* Done playing with pages, release the lock */
-    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
-    /* Decrement the number of data pages */
-    InterlockedDecrement(&MmSessionDataPages);
-
-    /* Free this session ID from the session bitmap */
-    KeAcquireGuardedMutex(&MiSessionIdMutex);
-    ASSERT(RtlCheckBit(MiSessionIdBitmap, SessionId));
-    RtlClearBit(MiSessionIdBitmap, SessionId);
-    KeReleaseGuardedMutex(&MiSessionIdMutex);
-}
-
-VOID
-NTAPI
-MiSessionRemoveProcess(VOID)
-{
-    PEPROCESS CurrentProcess = PsGetCurrentProcess();
-
-    /* If the process isn't already in a session, or if it's the leader... */
-    if (!(CurrentProcess->Flags & PSF_PROCESS_IN_SESSION_BIT) ||
-        (CurrentProcess->Vm.Flags.SessionLeader))
-    {
-        /* Then there's nothing to do */
-        return;
-    }
-
-    /* Sanity check */
-    ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
-
-    /* Remove the process from the list ,and dereference the session */
-    // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
-    //RemoveEntryList(&CurrentProcess->SessionProcessLinks);
-    //MiDereferenceSession();
-}
-
-VOID
-NTAPI
-MiSessionAddProcess(IN PEPROCESS NewProcess)
-{
-    PMM_SESSION_SPACE SessionGlobal;
-
-    /* The current process must already be in a session */
-    if (!(PsGetCurrentProcess()->Flags & PSF_PROCESS_IN_SESSION_BIT)) return;
-
-    /* Sanity check */
-    ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
-
-    /* Get the global session */
-    SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
-
-    /* Increment counters */
-    InterlockedIncrement((PLONG)&SessionGlobal->ReferenceCount);
-    InterlockedIncrement(&SessionGlobal->ResidentProcessCount);
-    InterlockedIncrement(&SessionGlobal->ProcessReferenceToSession);
-
-    /* Set the session pointer */
-    ASSERT(NewProcess->Session == NULL);
-    NewProcess->Session = SessionGlobal;
-
-    /* Insert it into the process list */
-    // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
-    //InsertTailList(&SessionGlobal->ProcessList, &NewProcess->SessionProcessLinks);
-
-    /* Set the flag */
-    PspSetProcessFlag(NewProcess, PSF_PROCESS_IN_SESSION_BIT);
-}
-
-NTSTATUS
-NTAPI
-MiSessionInitializeWorkingSetList(VOID)
-{
-    KIRQL OldIrql;
-    PMMPTE PointerPte, PointerPde;
-    MMPTE TempPte;
-    ULONG Color, Index;
-    PFN_NUMBER PageFrameIndex;
-    PMM_SESSION_SPACE SessionGlobal;
-    BOOLEAN AllocatedPageTable;
-    PMMWSL WorkingSetList;
-
-    /* Get pointers to session global and the session working set list */
-    SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
-    WorkingSetList = (PMMWSL)MiSessionSpaceWs;
-
-    /* Fill out the two pointers */
-    MmSessionSpace->Vm.VmWorkingSetList = WorkingSetList;
-    MmSessionSpace->Wsle = (PMMWSLE)WorkingSetList->UsedPageTableEntries;
-
-    /* Get the PDE for the working set, and check if it's already allocated */
-    PointerPde = MiAddressToPde(WorkingSetList);
-    if (PointerPde->u.Hard.Valid == 1)
-    {
-        /* Nope, we'll have to do it */
-        ASSERT(PointerPde->u.Hard.Global == 0);
-        AllocatedPageTable = FALSE;
-    }
-    else
-    {
-        /* Yep, that makes our job easier */
-        AllocatedPageTable = TRUE;
-    }
-
-    /* Get the PTE for the working set */
-    PointerPte = MiAddressToPte(WorkingSetList);
-
-    /* Initialize the working set lock, and lock the PFN database */
-    ExInitializePushLock(&SessionGlobal->Vm.WorkingSetMutex);
-    //MmLockPageableSectionByHandle(ExPageLockHandle);
-    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
-    /* Check if we need a page table */
-    if (AllocatedPageTable == TRUE)
-    {
-        /* Get a zeroed colored zero page */
-        Color = MI_GET_NEXT_COLOR();
-        PageFrameIndex = MiRemoveZeroPageSafe(Color);
-        if (!PageFrameIndex)
-        {
-            /* No zero pages, grab a free one */
-            PageFrameIndex = MiRemoveAnyPage(Color);
-
-            /* Zero it outside the PFN lock */
-            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-            MiZeroPhysicalPage(PageFrameIndex);
-            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-        }
-
-        /* Write a valid PDE for it */
-        TempPte.u.Long = ValidKernelPdeLocal.u.Long;
-        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
-        MI_WRITE_VALID_PTE(PointerPde, TempPte);
-
-        /* Add this into the list */
-        Index = ((ULONG_PTR)WorkingSetList - (ULONG_PTR)MmSessionBase) >> 22;
-#ifndef _M_AMD64
-        MmSessionSpace->PageTables[Index] = TempPte;
-#endif
-        /* Initialize the page directory page, and now zero the working set list itself */
-        MiInitializePfnForOtherProcess(PageFrameIndex,
-                                       PointerPde,
-                                       MmSessionSpace->SessionPageDirectoryIndex);
-        KeZeroPages(PointerPte, PAGE_SIZE);
-    }
-
-    /* Get a zeroed colored zero page */
-    Color = MI_GET_NEXT_COLOR();
-    PageFrameIndex = MiRemoveZeroPageSafe(Color);
-    if (!PageFrameIndex)
-    {
-        /* No zero pages, grab a free one */
-        PageFrameIndex = MiRemoveAnyPage(Color);
-
-        /* Zero it outside the PFN lock */
-        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-        MiZeroPhysicalPage(PageFrameIndex);
-        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    }
-
-    /* Write a valid PTE for it */
-    TempPte.u.Long = ValidKernelPteLocal.u.Long;
-    TempPte.u.Hard.Dirty = TRUE;
-    TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
-
-    /* Initialize the working set list page */
-    MiInitializePfnAndMakePteValid(PageFrameIndex, PointerPte, TempPte);
-
-    /* Now we can release the PFN database lock */
-    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
-    /* Fill out the working set structure */
-    MmSessionSpace->Vm.Flags.SessionSpace = 1;
-    MmSessionSpace->Vm.MinimumWorkingSetSize = 20;
-    MmSessionSpace->Vm.MaximumWorkingSetSize = 384;
-    WorkingSetList->LastEntry = 20;
-    WorkingSetList->HashTable = NULL;
-    WorkingSetList->HashTableSize = 0;
-    WorkingSetList->Wsle = MmSessionSpace->Wsle;
-
-    /* FIXME: Handle list insertions */
-    ASSERT(SessionGlobal->WsListEntry.Flink == NULL);
-    ASSERT(SessionGlobal->WsListEntry.Blink == NULL);
-    ASSERT(SessionGlobal->Vm.WorkingSetExpansionLinks.Flink == NULL);
-    ASSERT(SessionGlobal->Vm.WorkingSetExpansionLinks.Blink == NULL);
-
-    /* All done, return */
-    //MmUnlockPageableImageSection(ExPageLockHandle);
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-MiSessionCreateInternal(OUT PULONG SessionId)
-{
-    PEPROCESS Process = PsGetCurrentProcess();
-    ULONG NewFlags, Flags, Size, i, Color;
-    KIRQL OldIrql;
-    PMMPTE PointerPte, PageTables, SessionPte;
-    PMMPDE PointerPde;
-    PMM_SESSION_SPACE SessionGlobal;
-    MMPTE TempPte;
-    NTSTATUS Status;
-    BOOLEAN Result;
-    PFN_NUMBER SessionPageDirIndex;
-    PFN_NUMBER TagPage[MI_SESSION_TAG_PAGES_MAXIMUM];
-    PFN_NUMBER DataPage[MI_SESSION_DATA_PAGES_MAXIMUM];
-
-    /* This should not exist yet */
-    ASSERT(MmIsAddressValid(MmSessionSpace) == FALSE);
-
-    /* Loop so we can set the session-is-creating flag */
-    Flags = Process->Flags;
-    while (TRUE)
-    {
-        /* Check if it's already set */
-        if (Flags & PSF_SESSION_CREATION_UNDERWAY_BIT)
-        {
-            /* Bail out */
-            DPRINT1("Lost session race\n");
-            return STATUS_ALREADY_COMMITTED;
-        }
-
-        /* Now try to set it */
-        NewFlags = InterlockedCompareExchange((PLONG)&Process->Flags,
-                                              Flags | PSF_SESSION_CREATION_UNDERWAY_BIT,
-                                              Flags);
-        if (NewFlags == Flags) break;
-
-        /* It changed, try again */
-        Flags = NewFlags;
-    }
-
-    /* Now we should own the flag */
-    ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
-
-    /*
-     * Session space covers everything from 0xA0000000 to 0xC0000000.
-     * Allocate enough page tables to describe the entire region
-     */
-    Size = (0x20000000 / PDE_MAPPED_VA) * sizeof(MMPTE);
-    PageTables = ExAllocatePoolWithTag(NonPagedPool, Size, 'tHmM');
-    ASSERT(PageTables != NULL);
-    RtlZeroMemory(PageTables, Size);
-
-    /* Lock the session ID creation mutex */
-    KeAcquireGuardedMutex(&MiSessionIdMutex);
-
-    /* Allocate a new Session ID */
-    *SessionId = RtlFindClearBitsAndSet(MiSessionIdBitmap, 1, 0);
-    if (*SessionId == 0xFFFFFFFF)
-    {
-        /* We ran out of session IDs, we should expand */
-        DPRINT1("Too many sessions created. Expansion not yet supported\n");
-        ExFreePoolWithTag(PageTables, 'tHmM');
-        return STATUS_NO_MEMORY;
-    }
-
-    /* Unlock the session ID creation mutex */
-    KeReleaseGuardedMutex(&MiSessionIdMutex);
-
-    /* Reserve the global PTEs */
-    SessionPte = MiReserveSystemPtes(MiSessionDataPages, SystemPteSpace);
-    ASSERT(SessionPte != NULL);
-
-    /* Acquire the PFN lock while we set everything up */
-    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
-    /* Loop the global PTEs */
-    TempPte.u.Long = ValidKernelPte.u.Long;
-    for (i = 0; i < MiSessionDataPages; i++)
-    {
-        /* Get a zeroed colored zero page */
-        Color = MI_GET_NEXT_COLOR();
-        DataPage[i] = MiRemoveZeroPageSafe(Color);
-        if (!DataPage[i])
-        {
-            /* No zero pages, grab a free one */
-            DataPage[i] = MiRemoveAnyPage(Color);
-
-            /* Zero it outside the PFN lock */
-            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-            MiZeroPhysicalPage(DataPage[i]);
-            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-        }
-
-        /* Fill the PTE out */
-        TempPte.u.Hard.PageFrameNumber = DataPage[i];
-        MI_WRITE_VALID_PTE(SessionPte + i, TempPte);
-    }
-
-    /* Set the pointer to global space */
-    SessionGlobal = MiPteToAddress(SessionPte);
-
-    /* Get a zeroed colored zero page */
-    Color = MI_GET_NEXT_COLOR();
-    SessionPageDirIndex = MiRemoveZeroPageSafe(Color);
-    if (!SessionPageDirIndex)
-    {
-        /* No zero pages, grab a free one */
-        SessionPageDirIndex = MiRemoveAnyPage(Color);
-
-        /* Zero it outside the PFN lock */
-        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-        MiZeroPhysicalPage(SessionPageDirIndex);
-        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    }
-
-    /* Fill the PTE out */
-    TempPte.u.Long = ValidKernelPdeLocal.u.Long;
-    TempPte.u.Hard.PageFrameNumber = SessionPageDirIndex;
-
-    /* Setup, allocate, fill out the MmSessionSpace PTE */
-    PointerPde = MiAddressToPde(MmSessionSpace);
-    ASSERT(PointerPde->u.Long == 0);
-    MI_WRITE_VALID_PTE(PointerPde, TempPte);
-    MiInitializePfnForOtherProcess(SessionPageDirIndex,
-                                   PointerPde,
-                                   SessionPageDirIndex);
-    ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex)->u1.WsIndex == 0);
-
-     /* Loop all the local PTEs for it */
-    TempPte.u.Long = ValidKernelPteLocal.u.Long;
-    PointerPte = MiAddressToPte(MmSessionSpace);
-    for (i = 0; i < MiSessionDataPages; i++)
-    {
-        /* And fill them out */
-        TempPte.u.Hard.PageFrameNumber = DataPage[i];
-        MiInitializePfnAndMakePteValid(DataPage[i], PointerPte + i, TempPte);
-        ASSERT(MI_PFN_ELEMENT(DataPage[i])->u1.WsIndex == 0);
-    }
-
-     /* Finally loop all of the session pool tag pages */
-    for (i = 0; i < MiSessionTagPages; i++)
-    {
-        /* Grab a zeroed colored page */
-        Color = MI_GET_NEXT_COLOR();
-        TagPage[i] = MiRemoveZeroPageSafe(Color);
-        if (!TagPage[i])
-        {
-            /* No zero pages, grab a free one */
-            TagPage[i] = MiRemoveAnyPage(Color);
-
-            /* Zero it outside the PFN lock */
-            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-            MiZeroPhysicalPage(TagPage[i]);
-            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-        }
-
-        /* Fill the PTE out */
-        TempPte.u.Hard.PageFrameNumber = TagPage[i];
-        MiInitializePfnAndMakePteValid(TagPage[i],
-                                       PointerPte + MiSessionDataPages + i,
-                                       TempPte);
-    }
-
-    /* PTEs have been setup, release the PFN lock */
-    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
-    /* Fill out the session space structure now */
-    MmSessionSpace->GlobalVirtualAddress = SessionGlobal;
-    MmSessionSpace->ReferenceCount = 1;
-    MmSessionSpace->ResidentProcessCount = 1;
-    MmSessionSpace->u.LongFlags = 0;
-    MmSessionSpace->SessionId = *SessionId;
-    MmSessionSpace->LocaleId = PsDefaultSystemLocaleId;
-    MmSessionSpace->SessionPageDirectoryIndex = SessionPageDirIndex;
-    MmSessionSpace->Color = Color;
-    MmSessionSpace->NonPageablePages = MiSessionCreateCharge;
-    MmSessionSpace->CommittedPages = MiSessionCreateCharge;
-#ifndef _M_AMD64
-    MmSessionSpace->PageTables = PageTables;
-    MmSessionSpace->PageTables[PointerPde - MiAddressToPde(MmSessionBase)] = *PointerPde;
-#endif
-    InitializeListHead(&MmSessionSpace->ImageList);
-    DPRINT1("Session %lu is ready to go: 0x%p 0x%p, %lx 0x%p\n",
-            *SessionId, MmSessionSpace, SessionGlobal, SessionPageDirIndex, PageTables);
-
-    /* Initialize session pool */
-    //Status = MiInitializeSessionPool();
-    Status = STATUS_SUCCESS;
-    ASSERT(NT_SUCCESS(Status) == TRUE);
-
-    /* Initialize system space */
-    Result = MiInitializeSystemSpaceMap(&SessionGlobal->Session);
-    ASSERT(Result == TRUE);
-
-    /* Initialize the process list, make sure the workign set list is empty */
-    ASSERT(SessionGlobal->WsListEntry.Flink == NULL);
-    ASSERT(SessionGlobal->WsListEntry.Blink == NULL);
-    InitializeListHead(&SessionGlobal->ProcessList);
-
-    /* We're done, clear the flag */
-    ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
-    PspClearProcessFlag(Process, PSF_SESSION_CREATION_UNDERWAY_BIT);
-
-    /* Insert the process into the session  */
-    ASSERT(Process->Session == NULL);
-    ASSERT(SessionGlobal->ProcessReferenceToSession == 0);
-    SessionGlobal->ProcessReferenceToSession = 1;
-
-    /* We're done */
-    InterlockedIncrement(&MmSessionDataPages);
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-MmSessionCreate(OUT PULONG SessionId)
-{
-    PEPROCESS Process = PsGetCurrentProcess();
-    ULONG SessionLeaderExists;
-    NTSTATUS Status;
-
-    /* Fail if the process is already in a session */
-    if (Process->Flags & PSF_PROCESS_IN_SESSION_BIT)
-    {
-        DPRINT1("Process already in session\n");
-        return STATUS_ALREADY_COMMITTED;
-    }
-
-    /* Check if the process is already the session leader */
-    if (!Process->Vm.Flags.SessionLeader)
-    {
-        /* Atomically set it as the leader */
-        SessionLeaderExists = InterlockedCompareExchange(&MiSessionLeaderExists, 1, 0);
-        if (SessionLeaderExists)
-        {
-            DPRINT1("Session leader race\n");
-            return STATUS_INVALID_SYSTEM_SERVICE;
-        }
-
-        /* Do the work required to upgrade him */
-        MiSessionLeader(Process);
-    }
-
-    /* Create the session */
-    KeEnterCriticalRegion();
-    Status = MiSessionCreateInternal(SessionId);
-    if (!NT_SUCCESS(Status))
-    {
-        KeLeaveCriticalRegion();
-        return Status;
-    }
-
-    /* Set up the session working set */
-    Status = MiSessionInitializeWorkingSetList();
-    if (!NT_SUCCESS(Status))
-    {
-        /* Fail */
-        //MiDereferenceSession();
-        ASSERT(FALSE);
-        KeLeaveCriticalRegion();
-        return Status;
-    }
-
-    /* All done */
-    KeLeaveCriticalRegion();
-
-    /* Set and assert the flags, and return */
-    MmSessionSpace->u.Flags.Initialized = 1;
-    PspSetProcessFlag(Process, PSF_PROCESS_IN_SESSION_BIT);
-    ASSERT(MiSessionLeaderExists == 1);
-    return Status;
-}
-
-NTSTATUS
-NTAPI
-MmSessionDelete(IN ULONG SessionId)
-{
-    PEPROCESS Process = PsGetCurrentProcess();
-
-    /* Process must be in a session */
-    if (!(Process->Flags & PSF_PROCESS_IN_SESSION_BIT))
-    {
-        DPRINT1("Not in a session!\n");
-        return STATUS_UNABLE_TO_FREE_VM;
-    }
-
-    /* It must be the session leader */
-    if (!Process->Vm.Flags.SessionLeader)
-    {
-        DPRINT1("Not a session leader!\n");
-        return STATUS_UNABLE_TO_FREE_VM;
-    }
-
-    /* Remove one reference count */
-    KeEnterCriticalRegion();
-    /* FIXME: Do it */
-    KeLeaveCriticalRegion();
-
-    /* All done */
-    return STATUS_SUCCESS;
-}
 
 /* SYSTEM CALLS ***************************************************************/
 
diff --git a/reactos/ntoskrnl/mm/ARM3/session.c b/reactos/ntoskrnl/mm/ARM3/session.c
new file mode 100644 (file)
index 0000000..afd4f7c
--- /dev/null
@@ -0,0 +1,702 @@
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/mm/ARM3/session.c
+ * PURPOSE:         Session support routines
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+#define MODULE_INVOLVED_IN_ARM3
+#include "../ARM3/miarm.h"
+
+/* GLOBALS ********************************************************************/
+
+PMM_SESSION_SPACE MmSessionSpace;
+PFN_NUMBER MiSessionDataPages, MiSessionTagPages, MiSessionTagSizePages;
+PFN_NUMBER MiSessionBigPoolPages, MiSessionCreateCharge;
+KGUARDED_MUTEX MiSessionIdMutex;
+LONG MmSessionDataPages;
+PRTL_BITMAP MiSessionIdBitmap;
+volatile LONG MiSessionLeaderExists;
+
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+LCID
+NTAPI
+MmGetSessionLocaleId(VOID)
+{
+    PEPROCESS Process;
+    PAGED_CODE();
+
+    //
+    // Get the current process
+    //
+    Process = PsGetCurrentProcess();
+
+    //
+    // Check if it's the Session Leader
+    //
+    if (Process->Vm.Flags.SessionLeader)
+    {
+        //
+        // Make sure it has a valid Session
+        //
+        if (Process->Session)
+        {
+            //
+            // Get the Locale ID
+            //
+            return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
+        }
+    }
+
+    //
+    // Not a session leader, return the default
+    //
+    return PsDefaultThreadLocaleId;
+}
+
+VOID
+NTAPI
+MiInitializeSessionIds(VOID)
+{
+    ULONG Size, BitmapSize;
+    PFN_NUMBER TotalPages;
+
+    /* Setup the total number of data pages needed for the structure */
+    TotalPages = MI_SESSION_DATA_PAGES_MAXIMUM;
+    MiSessionDataPages = ROUND_TO_PAGES(sizeof(MM_SESSION_SPACE)) >> PAGE_SHIFT;
+    ASSERT(MiSessionDataPages <= MI_SESSION_DATA_PAGES_MAXIMUM - 3);
+    TotalPages -= MiSessionDataPages;
+
+    /* Setup the number of pages needed for session pool tags */
+    MiSessionTagSizePages = 2;
+    MiSessionBigPoolPages = 1;
+    MiSessionTagPages = MiSessionTagSizePages + MiSessionBigPoolPages;
+    ASSERT(MiSessionTagPages <= TotalPages);
+    ASSERT(MiSessionTagPages < MI_SESSION_TAG_PAGES_MAXIMUM);
+
+    /* Total pages needed for a session (FIXME: Probably different on PAE/x64) */
+    MiSessionCreateCharge = 1 + MiSessionDataPages + MiSessionTagPages;
+
+    /* Initialize the lock */
+    KeInitializeGuardedMutex(&MiSessionIdMutex);
+
+    /* Allocate the bitmap */
+    Size = MI_INITIAL_SESSION_IDS;
+    BitmapSize = ((Size + 31) / 32) * sizeof(ULONG);
+    MiSessionIdBitmap = ExAllocatePoolWithTag(PagedPool,
+                                              sizeof(RTL_BITMAP) + BitmapSize,
+                                              '  mM');
+    if (MiSessionIdBitmap)
+    {
+        /* Free all the bits */
+        RtlInitializeBitMap(MiSessionIdBitmap,
+                            (PVOID)(MiSessionIdBitmap + 1),
+                            Size);
+        RtlClearAllBits(MiSessionIdBitmap);
+    }
+    else
+    {
+        /* Die if we couldn't allocate the bitmap */
+        KeBugCheckEx(INSTALL_MORE_MEMORY,
+                     MmNumberOfPhysicalPages,
+                     MmLowestPhysicalPage,
+                     MmHighestPhysicalPage,
+                     0x200);
+    }
+}
+
+VOID
+NTAPI
+MiSessionLeader(IN PEPROCESS Process)
+{
+    KIRQL OldIrql;
+
+    /* Set the flag while under the expansion lock */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueueExpansionLock);
+    Process->Vm.Flags.SessionLeader = TRUE;
+    KeReleaseQueuedSpinLock(LockQueueExpansionLock, OldIrql);
+}
+
+ULONG
+NTAPI
+MmGetSessionId(IN PEPROCESS Process)
+{
+    PMM_SESSION_SPACE SessionGlobal;
+
+    /* The session leader is always session zero */
+    if (Process->Vm.Flags.SessionLeader == 1) return 0;
+
+    /* Otherwise, get the session global, and read the session ID from it */
+    SessionGlobal = (PMM_SESSION_SPACE)Process->Session;
+    if (!SessionGlobal) return 0;
+    return SessionGlobal->SessionId;
+}
+
+ULONG
+NTAPI
+MmGetSessionIdEx(IN PEPROCESS Process)
+{
+    PMM_SESSION_SPACE SessionGlobal;
+
+    /* The session leader is always session zero */
+    if (Process->Vm.Flags.SessionLeader == 1) return 0;
+
+    /* Otherwise, get the session global, and read the session ID from it */
+    SessionGlobal = (PMM_SESSION_SPACE)Process->Session;
+    if (!SessionGlobal) return -1;
+    return SessionGlobal->SessionId;
+}
+
+VOID
+NTAPI
+MiReleaseProcessReferenceToSessionDataPage(IN PMM_SESSION_SPACE SessionGlobal)
+{
+    ULONG i, SessionId;
+    PMMPTE PointerPte;
+    PFN_NUMBER PageFrameIndex[MI_SESSION_DATA_PAGES_MAXIMUM];
+    PMMPFN Pfn1;
+    KIRQL OldIrql;
+
+    /* Is there more than just this reference? If so, bail out */
+    if (InterlockedDecrement(&SessionGlobal->ProcessReferenceToSession)) return;
+
+    /* Get the session ID */
+    SessionId = SessionGlobal->SessionId;
+    DPRINT1("Last process in session %lu going down!!!\n", SessionId);
+
+    /* Free the session page tables */
+#ifndef _M_AMD64
+    ExFreePoolWithTag(SessionGlobal->PageTables, 'tHmM');
+#endif
+    ASSERT(!MI_IS_PHYSICAL_ADDRESS(SessionGlobal));
+
+    /* Capture the data page PFNs */
+    PointerPte = MiAddressToPte(SessionGlobal);
+    for (i = 0; i < MiSessionDataPages; i++)
+    {
+        PageFrameIndex[i] = PFN_FROM_PTE(PointerPte + i);
+    }
+
+    /* Release them */
+    MiReleaseSystemPtes(PointerPte, MiSessionDataPages, SystemPteSpace);
+
+    /* Mark them as deleted */
+    for (i = 0; i < MiSessionDataPages; i++)
+    {
+        Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
+        MI_SET_PFN_DELETED(Pfn1);
+    }
+
+    /* Loop every data page and drop a reference count */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    for (i = 0; i < MiSessionDataPages; i++)
+    {
+        /* Sanity check that the page is correct, then decrement it */
+        Pfn1 = MI_PFN_ELEMENT(PageFrameIndex[i]);
+        ASSERT(Pfn1->u2.ShareCount == 1);
+        ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
+        MiDecrementShareCount(Pfn1, PageFrameIndex[i]);
+    }
+
+    /* Done playing with pages, release the lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+    /* Decrement the number of data pages */
+    InterlockedDecrement(&MmSessionDataPages);
+
+    /* Free this session ID from the session bitmap */
+    KeAcquireGuardedMutex(&MiSessionIdMutex);
+    ASSERT(RtlCheckBit(MiSessionIdBitmap, SessionId));
+    RtlClearBit(MiSessionIdBitmap, SessionId);
+    KeReleaseGuardedMutex(&MiSessionIdMutex);
+}
+
+VOID
+NTAPI
+MiSessionRemoveProcess(VOID)
+{
+    PEPROCESS CurrentProcess = PsGetCurrentProcess();
+
+    /* If the process isn't already in a session, or if it's the leader... */
+    if (!(CurrentProcess->Flags & PSF_PROCESS_IN_SESSION_BIT) ||
+        (CurrentProcess->Vm.Flags.SessionLeader))
+    {
+        /* Then there's nothing to do */
+        return;
+    }
+
+    /* Sanity check */
+    ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
+
+    /* Remove the process from the list ,and dereference the session */
+    // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
+    //RemoveEntryList(&CurrentProcess->SessionProcessLinks);
+    //MiDereferenceSession();
+}
+
+VOID
+NTAPI
+MiSessionAddProcess(IN PEPROCESS NewProcess)
+{
+    PMM_SESSION_SPACE SessionGlobal;
+
+    /* The current process must already be in a session */
+    if (!(PsGetCurrentProcess()->Flags & PSF_PROCESS_IN_SESSION_BIT)) return;
+
+    /* Sanity check */
+    ASSERT(MmIsAddressValid(MmSessionSpace) == TRUE);
+
+    /* Get the global session */
+    SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
+
+    /* Increment counters */
+    InterlockedIncrement((PLONG)&SessionGlobal->ReferenceCount);
+    InterlockedIncrement(&SessionGlobal->ResidentProcessCount);
+    InterlockedIncrement(&SessionGlobal->ProcessReferenceToSession);
+
+    /* Set the session pointer */
+    ASSERT(NewProcess->Session == NULL);
+    NewProcess->Session = SessionGlobal;
+
+    /* Insert it into the process list */
+    // DO NOT ENABLE THIS UNLESS YOU FIXED THE NP POOL CORRUPTION THAT IT CAUSES!!!
+    //InsertTailList(&SessionGlobal->ProcessList, &NewProcess->SessionProcessLinks);
+
+    /* Set the flag */
+    PspSetProcessFlag(NewProcess, PSF_PROCESS_IN_SESSION_BIT);
+}
+
+NTSTATUS
+NTAPI
+MiSessionInitializeWorkingSetList(VOID)
+{
+    KIRQL OldIrql;
+    PMMPTE PointerPte, PointerPde;
+    MMPTE TempPte;
+    ULONG Color, Index;
+    PFN_NUMBER PageFrameIndex;
+    PMM_SESSION_SPACE SessionGlobal;
+    BOOLEAN AllocatedPageTable;
+    PMMWSL WorkingSetList;
+
+    /* Get pointers to session global and the session working set list */
+    SessionGlobal = MmSessionSpace->GlobalVirtualAddress;
+    WorkingSetList = (PMMWSL)MiSessionSpaceWs;
+
+    /* Fill out the two pointers */
+    MmSessionSpace->Vm.VmWorkingSetList = WorkingSetList;
+    MmSessionSpace->Wsle = (PMMWSLE)WorkingSetList->UsedPageTableEntries;
+
+    /* Get the PDE for the working set, and check if it's already allocated */
+    PointerPde = MiAddressToPde(WorkingSetList);
+    if (PointerPde->u.Hard.Valid == 1)
+    {
+        /* Nope, we'll have to do it */
+        ASSERT(PointerPde->u.Hard.Global == 0);
+        AllocatedPageTable = FALSE;
+    }
+    else
+    {
+        /* Yep, that makes our job easier */
+        AllocatedPageTable = TRUE;
+    }
+
+    /* Get the PTE for the working set */
+    PointerPte = MiAddressToPte(WorkingSetList);
+
+    /* Initialize the working set lock, and lock the PFN database */
+    ExInitializePushLock(&SessionGlobal->Vm.WorkingSetMutex);
+    //MmLockPageableSectionByHandle(ExPageLockHandle);
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Check if we need a page table */
+    if (AllocatedPageTable == TRUE)
+    {
+        /* Get a zeroed colored zero page */
+        Color = MI_GET_NEXT_COLOR();
+        PageFrameIndex = MiRemoveZeroPageSafe(Color);
+        if (!PageFrameIndex)
+        {
+            /* No zero pages, grab a free one */
+            PageFrameIndex = MiRemoveAnyPage(Color);
+
+            /* Zero it outside the PFN lock */
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+            MiZeroPhysicalPage(PageFrameIndex);
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+        }
+
+        /* Write a valid PDE for it */
+        TempPte.u.Long = ValidKernelPdeLocal.u.Long;
+        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        MI_WRITE_VALID_PTE(PointerPde, TempPte);
+
+        /* Add this into the list */
+        Index = ((ULONG_PTR)WorkingSetList - (ULONG_PTR)MmSessionBase) >> 22;
+#ifndef _M_AMD64
+        MmSessionSpace->PageTables[Index] = TempPte;
+#endif
+        /* Initialize the page directory page, and now zero the working set list itself */
+        MiInitializePfnForOtherProcess(PageFrameIndex,
+                                       PointerPde,
+                                       MmSessionSpace->SessionPageDirectoryIndex);
+        KeZeroPages(PointerPte, PAGE_SIZE);
+    }
+
+    /* Get a zeroed colored zero page */
+    Color = MI_GET_NEXT_COLOR();
+    PageFrameIndex = MiRemoveZeroPageSafe(Color);
+    if (!PageFrameIndex)
+    {
+        /* No zero pages, grab a free one */
+        PageFrameIndex = MiRemoveAnyPage(Color);
+
+        /* Zero it outside the PFN lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+        MiZeroPhysicalPage(PageFrameIndex);
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    }
+
+    /* Write a valid PTE for it */
+    TempPte.u.Long = ValidKernelPteLocal.u.Long;
+    TempPte.u.Hard.Dirty = TRUE;
+    TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+
+    /* Initialize the working set list page */
+    MiInitializePfnAndMakePteValid(PageFrameIndex, PointerPte, TempPte);
+
+    /* Now we can release the PFN database lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+    /* Fill out the working set structure */
+    MmSessionSpace->Vm.Flags.SessionSpace = 1;
+    MmSessionSpace->Vm.MinimumWorkingSetSize = 20;
+    MmSessionSpace->Vm.MaximumWorkingSetSize = 384;
+    WorkingSetList->LastEntry = 20;
+    WorkingSetList->HashTable = NULL;
+    WorkingSetList->HashTableSize = 0;
+    WorkingSetList->Wsle = MmSessionSpace->Wsle;
+
+    /* FIXME: Handle list insertions */
+    ASSERT(SessionGlobal->WsListEntry.Flink == NULL);
+    ASSERT(SessionGlobal->WsListEntry.Blink == NULL);
+    ASSERT(SessionGlobal->Vm.WorkingSetExpansionLinks.Flink == NULL);
+    ASSERT(SessionGlobal->Vm.WorkingSetExpansionLinks.Blink == NULL);
+
+    /* All done, return */
+    //MmUnlockPageableImageSection(ExPageLockHandle);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiSessionCreateInternal(OUT PULONG SessionId)
+{
+    PEPROCESS Process = PsGetCurrentProcess();
+    ULONG NewFlags, Flags, Size, i, Color;
+    KIRQL OldIrql;
+    PMMPTE PointerPte, PageTables, SessionPte;
+    PMMPDE PointerPde;
+    PMM_SESSION_SPACE SessionGlobal;
+    MMPTE TempPte;
+    NTSTATUS Status;
+    BOOLEAN Result;
+    PFN_NUMBER SessionPageDirIndex;
+    PFN_NUMBER TagPage[MI_SESSION_TAG_PAGES_MAXIMUM];
+    PFN_NUMBER DataPage[MI_SESSION_DATA_PAGES_MAXIMUM];
+
+    /* This should not exist yet */
+    ASSERT(MmIsAddressValid(MmSessionSpace) == FALSE);
+
+    /* Loop so we can set the session-is-creating flag */
+    Flags = Process->Flags;
+    while (TRUE)
+    {
+        /* Check if it's already set */
+        if (Flags & PSF_SESSION_CREATION_UNDERWAY_BIT)
+        {
+            /* Bail out */
+            DPRINT1("Lost session race\n");
+            return STATUS_ALREADY_COMMITTED;
+        }
+
+        /* Now try to set it */
+        NewFlags = InterlockedCompareExchange((PLONG)&Process->Flags,
+                                              Flags | PSF_SESSION_CREATION_UNDERWAY_BIT,
+                                              Flags);
+        if (NewFlags == Flags) break;
+
+        /* It changed, try again */
+        Flags = NewFlags;
+    }
+
+    /* Now we should own the flag */
+    ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
+
+    /*
+     * Session space covers everything from 0xA0000000 to 0xC0000000.
+     * Allocate enough page tables to describe the entire region
+     */
+    Size = (0x20000000 / PDE_MAPPED_VA) * sizeof(MMPTE);
+    PageTables = ExAllocatePoolWithTag(NonPagedPool, Size, 'tHmM');
+    ASSERT(PageTables != NULL);
+    RtlZeroMemory(PageTables, Size);
+
+    /* Lock the session ID creation mutex */
+    KeAcquireGuardedMutex(&MiSessionIdMutex);
+
+    /* Allocate a new Session ID */
+    *SessionId = RtlFindClearBitsAndSet(MiSessionIdBitmap, 1, 0);
+    if (*SessionId == 0xFFFFFFFF)
+    {
+        /* We ran out of session IDs, we should expand */
+        DPRINT1("Too many sessions created. Expansion not yet supported\n");
+        ExFreePoolWithTag(PageTables, 'tHmM');
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Unlock the session ID creation mutex */
+    KeReleaseGuardedMutex(&MiSessionIdMutex);
+
+    /* Reserve the global PTEs */
+    SessionPte = MiReserveSystemPtes(MiSessionDataPages, SystemPteSpace);
+    ASSERT(SessionPte != NULL);
+
+    /* Acquire the PFN lock while we set everything up */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Loop the global PTEs */
+    TempPte.u.Long = ValidKernelPte.u.Long;
+    for (i = 0; i < MiSessionDataPages; i++)
+    {
+        /* Get a zeroed colored zero page */
+        Color = MI_GET_NEXT_COLOR();
+        DataPage[i] = MiRemoveZeroPageSafe(Color);
+        if (!DataPage[i])
+        {
+            /* No zero pages, grab a free one */
+            DataPage[i] = MiRemoveAnyPage(Color);
+
+            /* Zero it outside the PFN lock */
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+            MiZeroPhysicalPage(DataPage[i]);
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+        }
+
+        /* Fill the PTE out */
+        TempPte.u.Hard.PageFrameNumber = DataPage[i];
+        MI_WRITE_VALID_PTE(SessionPte + i, TempPte);
+    }
+
+    /* Set the pointer to global space */
+    SessionGlobal = MiPteToAddress(SessionPte);
+
+    /* Get a zeroed colored zero page */
+    Color = MI_GET_NEXT_COLOR();
+    SessionPageDirIndex = MiRemoveZeroPageSafe(Color);
+    if (!SessionPageDirIndex)
+    {
+        /* No zero pages, grab a free one */
+        SessionPageDirIndex = MiRemoveAnyPage(Color);
+
+        /* Zero it outside the PFN lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+        MiZeroPhysicalPage(SessionPageDirIndex);
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    }
+
+    /* Fill the PTE out */
+    TempPte.u.Long = ValidKernelPdeLocal.u.Long;
+    TempPte.u.Hard.PageFrameNumber = SessionPageDirIndex;
+
+    /* Setup, allocate, fill out the MmSessionSpace PTE */
+    PointerPde = MiAddressToPde(MmSessionSpace);
+    ASSERT(PointerPde->u.Long == 0);
+    MI_WRITE_VALID_PTE(PointerPde, TempPte);
+    MiInitializePfnForOtherProcess(SessionPageDirIndex,
+                                   PointerPde,
+                                   SessionPageDirIndex);
+    ASSERT(MI_PFN_ELEMENT(SessionPageDirIndex)->u1.WsIndex == 0);
+
+     /* Loop all the local PTEs for it */
+    TempPte.u.Long = ValidKernelPteLocal.u.Long;
+    PointerPte = MiAddressToPte(MmSessionSpace);
+    for (i = 0; i < MiSessionDataPages; i++)
+    {
+        /* And fill them out */
+        TempPte.u.Hard.PageFrameNumber = DataPage[i];
+        MiInitializePfnAndMakePteValid(DataPage[i], PointerPte + i, TempPte);
+        ASSERT(MI_PFN_ELEMENT(DataPage[i])->u1.WsIndex == 0);
+    }
+
+     /* Finally loop all of the session pool tag pages */
+    for (i = 0; i < MiSessionTagPages; i++)
+    {
+        /* Grab a zeroed colored page */
+        Color = MI_GET_NEXT_COLOR();
+        TagPage[i] = MiRemoveZeroPageSafe(Color);
+        if (!TagPage[i])
+        {
+            /* No zero pages, grab a free one */
+            TagPage[i] = MiRemoveAnyPage(Color);
+
+            /* Zero it outside the PFN lock */
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+            MiZeroPhysicalPage(TagPage[i]);
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+        }
+
+        /* Fill the PTE out */
+        TempPte.u.Hard.PageFrameNumber = TagPage[i];
+        MiInitializePfnAndMakePteValid(TagPage[i],
+                                       PointerPte + MiSessionDataPages + i,
+                                       TempPte);
+    }
+
+    /* PTEs have been setup, release the PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+    /* Fill out the session space structure now */
+    MmSessionSpace->GlobalVirtualAddress = SessionGlobal;
+    MmSessionSpace->ReferenceCount = 1;
+    MmSessionSpace->ResidentProcessCount = 1;
+    MmSessionSpace->u.LongFlags = 0;
+    MmSessionSpace->SessionId = *SessionId;
+    MmSessionSpace->LocaleId = PsDefaultSystemLocaleId;
+    MmSessionSpace->SessionPageDirectoryIndex = SessionPageDirIndex;
+    MmSessionSpace->Color = Color;
+    MmSessionSpace->NonPageablePages = MiSessionCreateCharge;
+    MmSessionSpace->CommittedPages = MiSessionCreateCharge;
+#ifndef _M_AMD64
+    MmSessionSpace->PageTables = PageTables;
+    MmSessionSpace->PageTables[PointerPde - MiAddressToPde(MmSessionBase)] = *PointerPde;
+#endif
+    InitializeListHead(&MmSessionSpace->ImageList);
+    DPRINT1("Session %lu is ready to go: 0x%p 0x%p, %lx 0x%p\n",
+            *SessionId, MmSessionSpace, SessionGlobal, SessionPageDirIndex, PageTables);
+
+    /* Initialize session pool */
+    //Status = MiInitializeSessionPool();
+    Status = STATUS_SUCCESS;
+    ASSERT(NT_SUCCESS(Status) == TRUE);
+
+    /* Initialize system space */
+    Result = MiInitializeSystemSpaceMap(&SessionGlobal->Session);
+    ASSERT(Result == TRUE);
+
+    /* Initialize the process list, make sure the workign set list is empty */
+    ASSERT(SessionGlobal->WsListEntry.Flink == NULL);
+    ASSERT(SessionGlobal->WsListEntry.Blink == NULL);
+    InitializeListHead(&SessionGlobal->ProcessList);
+
+    /* We're done, clear the flag */
+    ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
+    PspClearProcessFlag(Process, PSF_SESSION_CREATION_UNDERWAY_BIT);
+
+    /* Insert the process into the session  */
+    ASSERT(Process->Session == NULL);
+    ASSERT(SessionGlobal->ProcessReferenceToSession == 0);
+    SessionGlobal->ProcessReferenceToSession = 1;
+
+    /* We're done */
+    InterlockedIncrement(&MmSessionDataPages);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmSessionCreate(OUT PULONG SessionId)
+{
+    PEPROCESS Process = PsGetCurrentProcess();
+    ULONG SessionLeaderExists;
+    NTSTATUS Status;
+
+    /* Fail if the process is already in a session */
+    if (Process->Flags & PSF_PROCESS_IN_SESSION_BIT)
+    {
+        DPRINT1("Process already in session\n");
+        return STATUS_ALREADY_COMMITTED;
+    }
+
+    /* Check if the process is already the session leader */
+    if (!Process->Vm.Flags.SessionLeader)
+    {
+        /* Atomically set it as the leader */
+        SessionLeaderExists = InterlockedCompareExchange(&MiSessionLeaderExists, 1, 0);
+        if (SessionLeaderExists)
+        {
+            DPRINT1("Session leader race\n");
+            return STATUS_INVALID_SYSTEM_SERVICE;
+        }
+
+        /* Do the work required to upgrade him */
+        MiSessionLeader(Process);
+    }
+
+    /* Create the session */
+    KeEnterCriticalRegion();
+    Status = MiSessionCreateInternal(SessionId);
+    if (!NT_SUCCESS(Status))
+    {
+        KeLeaveCriticalRegion();
+        return Status;
+    }
+
+    /* Set up the session working set */
+    Status = MiSessionInitializeWorkingSetList();
+    if (!NT_SUCCESS(Status))
+    {
+        /* Fail */
+        //MiDereferenceSession();
+        ASSERT(FALSE);
+        KeLeaveCriticalRegion();
+        return Status;
+    }
+
+    /* All done */
+    KeLeaveCriticalRegion();
+
+    /* Set and assert the flags, and return */
+    MmSessionSpace->u.Flags.Initialized = 1;
+    PspSetProcessFlag(Process, PSF_PROCESS_IN_SESSION_BIT);
+    ASSERT(MiSessionLeaderExists == 1);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+MmSessionDelete(IN ULONG SessionId)
+{
+    PEPROCESS Process = PsGetCurrentProcess();
+
+    /* Process must be in a session */
+    if (!(Process->Flags & PSF_PROCESS_IN_SESSION_BIT))
+    {
+        DPRINT1("Not in a session!\n");
+        return STATUS_UNABLE_TO_FREE_VM;
+    }
+
+    /* It must be the session leader */
+    if (!Process->Vm.Flags.SessionLeader)
+    {
+        DPRINT1("Not a session leader!\n");
+        return STATUS_UNABLE_TO_FREE_VM;
+    }
+
+    /* Remove one reference count */
+    KeEnterCriticalRegion();
+    /* FIXME: Do it */
+    KeLeaveCriticalRegion();
+
+    /* All done */
+    return STATUS_SUCCESS;
+}