ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

procsup.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/mm/ARM3/procsup.c
00005  * PURPOSE:         ARM Memory Manager Process Related Management
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 #define MODULE_INVOLVED_IN_ARM3
00016 #include "../ARM3/miarm.h"
00017 
00018 /* GLOBALS ********************************************************************/
00019 
00020 ULONG MmProcessColorSeed = 0x12345678;
00021 PMMWSL MmWorkingSetList;
00022 ULONG MmMaximumDeadKernelStacks = 5;
00023 SLIST_HEADER MmDeadStackSListHead;
00024 
00025 /* PRIVATE FUNCTIONS **********************************************************/
00026 
00027 VOID
00028 NTAPI
00029 MiRosTakeOverSharedUserPage(IN PEPROCESS Process)
00030 {
00031     NTSTATUS Status;
00032     PMEMORY_AREA MemoryArea;
00033     PHYSICAL_ADDRESS BoundaryAddressMultiple;
00034     PVOID AllocatedBase = (PVOID)MM_SHARED_USER_DATA_VA;
00035     BoundaryAddressMultiple.QuadPart = 0;
00036 
00037     Status = MmCreateMemoryArea(&Process->Vm,
00038                                 MEMORY_AREA_OWNED_BY_ARM3,
00039                                 &AllocatedBase,
00040                                 PAGE_SIZE,
00041                                 PAGE_READWRITE,
00042                                 &MemoryArea,
00043                                 TRUE,
00044                                 0,
00045                                 BoundaryAddressMultiple);
00046     ASSERT(NT_SUCCESS(Status));
00047 }
00048 
00049 NTSTATUS
00050 NTAPI
00051 MiCreatePebOrTeb(IN PEPROCESS Process,
00052                  IN ULONG Size,
00053                  OUT PULONG_PTR Base)
00054 {
00055     PETHREAD Thread = PsGetCurrentThread();
00056     PMMVAD_LONG Vad;
00057     NTSTATUS Status;
00058     ULONG RandomCoeff;
00059     ULONG_PTR StartAddress, EndAddress;
00060     LARGE_INTEGER CurrentTime;
00061     TABLE_SEARCH_RESULT Result = TableFoundNode;
00062     PMMADDRESS_NODE Parent;
00063 
00064     /* Allocate a VAD */
00065     Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV');
00066     if (!Vad) return STATUS_NO_MEMORY;
00067 
00068     /* Setup the primary flags with the size, and make it commited, private, RW */
00069     Vad->u.LongFlags = 0;
00070     Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size);
00071     Vad->u.VadFlags.MemCommit = TRUE;
00072     Vad->u.VadFlags.PrivateMemory = TRUE;
00073     Vad->u.VadFlags.Protection = MM_READWRITE;
00074     Vad->u.VadFlags.NoChange = TRUE;
00075 
00076     /* Setup the secondary flags to make it a secured, writable, long VAD */
00077     Vad->u2.LongFlags2 = 0;
00078     Vad->u2.VadFlags2.OneSecured = TRUE;
00079     Vad->u2.VadFlags2.LongVad = TRUE;
00080     Vad->u2.VadFlags2.ReadOnly = FALSE;
00081 
00082     /* Lock the process address space */
00083     KeAcquireGuardedMutex(&Process->AddressCreationLock);
00084 
00085     /* Check if this is a PEB creation */
00086     if (Size == sizeof(PEB))
00087     {
00088         /* Start at the highest valid address */
00089         StartAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1;
00090 
00091         /* Select the random coefficient */
00092         KeQueryTickCount(&CurrentTime);
00093         CurrentTime.LowPart &= ((64 * _1KB) >> PAGE_SHIFT) - 1;
00094         if (CurrentTime.LowPart <= 1) CurrentTime.LowPart = 2;
00095         RandomCoeff = CurrentTime.LowPart << PAGE_SHIFT;
00096 
00097         /* Select the highest valid address minus the random coefficient */
00098         StartAddress -= RandomCoeff;
00099         EndAddress = StartAddress + ROUND_TO_PAGES(Size) - 1;
00100 
00101         /* Try to find something below the random upper margin */
00102         Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
00103                                                  EndAddress,
00104                                                  PAGE_SIZE,
00105                                                  &Process->VadRoot,
00106                                                  Base,
00107                                                  &Parent);
00108     }
00109 
00110     /* Check for success. TableFoundNode means nothing free. */
00111     if (Result == TableFoundNode)
00112     {
00113         /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
00114         Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
00115                                                  (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1,
00116                                                  PAGE_SIZE,
00117                                                  &Process->VadRoot,
00118                                                  Base,
00119                                                  &Parent);
00120         /* Bail out, if still nothing free was found */
00121         if (Result == TableFoundNode) return STATUS_NO_MEMORY;
00122     }
00123 
00124     /* Validate that it came from the VAD ranges */
00125     ASSERT(*Base >= (ULONG_PTR)MI_LOWEST_VAD_ADDRESS);
00126 
00127     /* Build the rest of the VAD now */
00128     Vad->StartingVpn = (*Base) >> PAGE_SHIFT;
00129     Vad->EndingVpn = ((*Base) + Size - 1) >> PAGE_SHIFT;
00130     Vad->u3.Secured.StartVpn = *Base;
00131     Vad->u3.Secured.EndVpn = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
00132     Vad->u1.Parent = NULL;
00133 
00134     /* FIXME: Should setup VAD bitmap */
00135     Status = STATUS_SUCCESS;
00136 
00137     /* Pretend as if we own the working set */
00138     MiLockProcessWorkingSet(Process, Thread);
00139 
00140     /* Insert the VAD */
00141     ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
00142     Process->VadRoot.NodeHint = Vad;
00143     Vad->ControlArea = NULL; // For Memory-Area hack
00144     Vad->FirstPrototypePte = NULL;
00145     DPRINT("VAD: %p\n", Vad);
00146     DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
00147     MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
00148 
00149     /* Release the working set */
00150     MiUnlockProcessWorkingSet(Process, Thread);
00151 
00152     /* Release the address space lock */
00153     KeReleaseGuardedMutex(&Process->AddressCreationLock);
00154 
00155     /* Return the status */
00156     return Status;
00157 }
00158 
00159 VOID
00160 NTAPI
00161 MmDeleteTeb(IN PEPROCESS Process,
00162             IN PTEB Teb)
00163 {
00164     ULONG_PTR TebEnd;
00165     PETHREAD Thread = PsGetCurrentThread();
00166     PMMVAD Vad;
00167     PMM_AVL_TABLE VadTree = &Process->VadRoot;
00168     DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName);
00169 
00170     /* TEB is one page */
00171     TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1;
00172 
00173     /* Attach to the process */
00174     KeAttachProcess(&Process->Pcb);
00175 
00176     /* Lock the process address space */
00177     KeAcquireGuardedMutex(&Process->AddressCreationLock);
00178 
00179     /* Find the VAD, make sure it's a TEB VAD */
00180     Vad = MiLocateAddress(Teb);
00181     DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn);
00182     ASSERT(Vad != NULL);
00183     if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT))
00184     {
00185         /* Bug in the AVL code? */
00186         DPRINT1("Corrupted VAD!\n");
00187     }
00188     else
00189     {
00190         /* Sanity checks for a valid TEB VAD */
00191         ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) &&
00192                (Vad->EndingVpn == (TebEnd >> PAGE_SHIFT))));
00193         ASSERT(Vad->u.VadFlags.NoChange == TRUE);
00194         ASSERT(Vad->u2.VadFlags2.OneSecured == TRUE);
00195         ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE);
00196 
00197         /* Lock the working set */
00198         MiLockProcessWorkingSet(Process, Thread);
00199 
00200         /* Remove this VAD from the tree */
00201         ASSERT(VadTree->NumberGenericTableElements >= 1);
00202         MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
00203 
00204         /* Delete the pages */
00205         MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL);
00206 
00207         /* Release the working set */
00208         MiUnlockProcessWorkingSet(Process, Thread);
00209 
00210         /* Remove the VAD */
00211         ExFreePool(Vad);
00212     }
00213 
00214     /* Release the address space lock */
00215     KeReleaseGuardedMutex(&Process->AddressCreationLock);
00216 
00217     /* Detach */
00218     KeDetachProcess();
00219 }
00220 
00221 VOID
00222 NTAPI
00223 MmDeleteKernelStack(IN PVOID StackBase,
00224                     IN BOOLEAN GuiStack)
00225 {
00226     PMMPTE PointerPte;
00227     PFN_NUMBER PageFrameNumber, PageTableFrameNumber;
00228     PFN_COUNT StackPages;
00229     PMMPFN Pfn1, Pfn2;
00230     ULONG i;
00231     KIRQL OldIrql;
00232 
00233     //
00234     // This should be the guard page, so decrement by one
00235     //
00236     PointerPte = MiAddressToPte(StackBase);
00237     PointerPte--;
00238 
00239     //
00240     // If this is a small stack, just push the stack onto the dead stack S-LIST
00241     //
00242     if (!GuiStack)
00243     {
00244         if (ExQueryDepthSList(&MmDeadStackSListHead) < MmMaximumDeadKernelStacks)
00245         {
00246             Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
00247             InterlockedPushEntrySList(&MmDeadStackSListHead,
00248                                       (PSLIST_ENTRY)&Pfn1->u1.NextStackPfn);
00249             return;
00250         }
00251     }
00252 
00253     //
00254     // Calculate pages used
00255     //
00256     StackPages = BYTES_TO_PAGES(GuiStack ?
00257                                 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
00258 
00259     /* Acquire the PFN lock */
00260     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00261 
00262     //
00263     // Loop them
00264     //
00265     for (i = 0; i < StackPages; i++)
00266     {
00267         //
00268         // Check if this is a valid PTE
00269         //
00270         if (PointerPte->u.Hard.Valid == 1)
00271         {
00272             /* Get the PTE's page */
00273             PageFrameNumber = PFN_FROM_PTE(PointerPte);
00274             Pfn1 = MiGetPfnEntry(PageFrameNumber);
00275 
00276             /* Now get the page of the page table mapping it */
00277             PageTableFrameNumber = Pfn1->u4.PteFrame;
00278             Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
00279 
00280             /* Remove a shared reference, since the page is going away */
00281             MiDecrementShareCount(Pfn2, PageTableFrameNumber);
00282 
00283             /* Set the special pending delete marker */
00284             MI_SET_PFN_DELETED(Pfn1);
00285 
00286             /* And now delete the actual stack page */
00287             MiDecrementShareCount(Pfn1, PageFrameNumber);
00288         }
00289 
00290         //
00291         // Next one
00292         //
00293         PointerPte--;
00294     }
00295 
00296     //
00297     // We should be at the guard page now
00298     //
00299     ASSERT(PointerPte->u.Hard.Valid == 0);
00300 
00301     /* Release the PFN lock */
00302     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00303 
00304     //
00305     // Release the PTEs
00306     //
00307     MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace);
00308 }
00309 
00310 PVOID
00311 NTAPI
00312 MmCreateKernelStack(IN BOOLEAN GuiStack,
00313                     IN UCHAR Node)
00314 {
00315     PFN_COUNT StackPtes, StackPages;
00316     PMMPTE PointerPte, StackPte;
00317     PVOID BaseAddress;
00318     MMPTE TempPte, InvalidPte;
00319     KIRQL OldIrql;
00320     PFN_NUMBER PageFrameIndex;
00321     ULONG i;
00322     PMMPFN Pfn1;
00323 
00324     //
00325     // Calculate pages needed
00326     //
00327     if (GuiStack)
00328     {
00329         //
00330         // We'll allocate 64KB stack, but only commit 12K
00331         //
00332         StackPtes = BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE);
00333         StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT);
00334 
00335     }
00336     else
00337     {
00338         //
00339         // If the dead stack S-LIST has a stack on it, use it instead of allocating
00340         // new system PTEs for this stack
00341         //
00342         if (ExQueryDepthSList(&MmDeadStackSListHead))
00343         {
00344             Pfn1 = (PMMPFN)InterlockedPopEntrySList(&MmDeadStackSListHead);
00345             if (Pfn1)
00346             {
00347                 PointerPte = Pfn1->PteAddress;
00348                 BaseAddress = MiPteToAddress(++PointerPte);
00349                 return BaseAddress;
00350             }
00351         }
00352 
00353         //
00354         // We'll allocate 12K and that's it
00355         //
00356         StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE);
00357         StackPages = StackPtes;
00358     }
00359 
00360     //
00361     // Reserve stack pages, plus a guard page
00362     //
00363     StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace);
00364     if (!StackPte) return NULL;
00365 
00366     //
00367     // Get the stack address
00368     //
00369     BaseAddress = MiPteToAddress(StackPte + StackPtes + 1);
00370 
00371     //
00372     // Select the right PTE address where we actually start committing pages
00373     //
00374     PointerPte = StackPte;
00375     if (GuiStack) PointerPte += BYTES_TO_PAGES(KERNEL_LARGE_STACK_SIZE -
00376                                                KERNEL_LARGE_STACK_COMMIT);
00377 
00378 
00379     /* Setup the temporary invalid PTE */
00380     MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
00381 
00382     /* Setup the template stack PTE */
00383     MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
00384 
00385     //
00386     // Acquire the PFN DB lock
00387     //
00388     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00389 
00390     //
00391     // Loop each stack page
00392     //
00393     for (i = 0; i < StackPages; i++)
00394     {
00395         //
00396         // Next PTE
00397         //
00398         PointerPte++;
00399 
00400         /* Get a page and write the current invalid PTE */
00401         MI_SET_USAGE(MI_USAGE_KERNEL_STACK);
00402         MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
00403         PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
00404         MI_WRITE_INVALID_PTE(PointerPte, InvalidPte);
00405 
00406         /* Initialize the PFN entry for this page */
00407         MiInitializePfn(PageFrameIndex, PointerPte, 1);
00408 
00409         /* Write the valid PTE */
00410         TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
00411         MI_WRITE_VALID_PTE(PointerPte, TempPte);
00412     }
00413 
00414     //
00415     // Release the PFN lock
00416     //
00417     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00418 
00419     //
00420     // Return the stack address
00421     //
00422     return BaseAddress;
00423 }
00424 
00425 NTSTATUS
00426 NTAPI
00427 MmGrowKernelStackEx(IN PVOID StackPointer,
00428                     IN ULONG GrowSize)
00429 {
00430     PKTHREAD Thread = KeGetCurrentThread();
00431     PMMPTE LimitPte, NewLimitPte, LastPte;
00432     KIRQL OldIrql;
00433     MMPTE TempPte, InvalidPte;
00434     PFN_NUMBER PageFrameIndex;
00435 
00436     //
00437     // Make sure the stack did not overflow
00438     //
00439     ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <=
00440            (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE));
00441 
00442     //
00443     // Get the current stack limit
00444     //
00445     LimitPte = MiAddressToPte(Thread->StackLimit);
00446     ASSERT(LimitPte->u.Hard.Valid == 1);
00447 
00448     //
00449     // Get the new one and make sure this isn't a retarded request
00450     //
00451     NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize));
00452     if (NewLimitPte == LimitPte) return STATUS_SUCCESS;
00453 
00454     //
00455     // Now make sure you're not going past the reserved space
00456     //
00457     LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase -
00458                                      KERNEL_LARGE_STACK_SIZE));
00459     if (NewLimitPte < LastPte)
00460     {
00461         //
00462         // Sorry!
00463         //
00464         DPRINT1("Thread wants too much stack\n");
00465         return STATUS_STACK_OVERFLOW;
00466     }
00467 
00468     //
00469     // Calculate the number of new pages
00470     //
00471     LimitPte--;
00472 
00473     /* Setup the temporary invalid PTE */
00474     MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
00475 
00476     //
00477     // Acquire the PFN DB lock
00478     //
00479     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00480 
00481     //
00482     // Loop each stack page
00483     //
00484     while (LimitPte >= NewLimitPte)
00485     {
00486         /* Get a page and write the current invalid PTE */
00487         MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION);
00488         MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
00489         PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
00490         MI_WRITE_INVALID_PTE(LimitPte, InvalidPte);
00491 
00492         /* Initialize the PFN entry for this page */
00493         MiInitializePfn(PageFrameIndex, LimitPte, 1);
00494 
00495         /* Setup the template stack PTE */
00496         MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
00497 
00498         /* Write the valid PTE */
00499         MI_WRITE_VALID_PTE(LimitPte--, TempPte);
00500     }
00501 
00502     //
00503     // Release the PFN lock
00504     //
00505     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00506 
00507     //
00508     // Set the new limit
00509     //
00510     Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte);
00511     return STATUS_SUCCESS;
00512 }
00513 
00514 NTSTATUS
00515 NTAPI
00516 MmGrowKernelStack(IN PVOID StackPointer)
00517 {
00518     //
00519     // Call the extended version
00520     //
00521     return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT);
00522 }
00523 
00524 NTSTATUS
00525 NTAPI
00526 MmSetMemoryPriorityProcess(IN PEPROCESS Process,
00527                            IN UCHAR MemoryPriority)
00528 {
00529     UCHAR OldPriority;
00530 
00531     //
00532     // Check if we have less then 16MB of Physical Memory
00533     //
00534     if ((MmSystemSize == MmSmallSystem) &&
00535         (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
00536     {
00537         //
00538         // Always use background priority
00539         //
00540         MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
00541     }
00542 
00543     //
00544     // Save the old priority and update it
00545     //
00546     OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority;
00547     Process->Vm.Flags.MemoryPriority = MemoryPriority;
00548 
00549     //
00550     // Return the old priority
00551     //
00552     return OldPriority;
00553 }
00554 
00555 LCID
00556 NTAPI
00557 MmGetSessionLocaleId(VOID)
00558 {
00559     PEPROCESS Process;
00560     PAGED_CODE();
00561 
00562     //
00563     // Get the current process
00564     //
00565     Process = PsGetCurrentProcess();
00566 
00567     //
00568     // Check if it's the Session Leader
00569     //
00570     if (Process->Vm.Flags.SessionLeader)
00571     {
00572         //
00573         // Make sure it has a valid Session
00574         //
00575         if (Process->Session)
00576         {
00577             //
00578             // Get the Locale ID
00579             //
00580 #if ROS_HAS_SESSIONS
00581             return ((PMM_SESSION_SPACE)Process->Session)->LocaleId;
00582 #endif
00583         }
00584     }
00585 
00586     //
00587     // Not a session leader, return the default
00588     //
00589     return PsDefaultThreadLocaleId;
00590 }
00591 
00592 NTSTATUS
00593 NTAPI
00594 MmCreatePeb(IN PEPROCESS Process,
00595             IN PINITIAL_PEB InitialPeb,
00596             OUT PPEB *BasePeb)
00597 {
00598     PPEB Peb = NULL;
00599     LARGE_INTEGER SectionOffset;
00600     SIZE_T ViewSize = 0;
00601     PVOID TableBase = NULL;
00602     PIMAGE_NT_HEADERS NtHeaders;
00603     PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
00604     NTSTATUS Status;
00605     USHORT Characteristics;
00606     KAFFINITY ProcessAffinityMask = 0;
00607     SectionOffset.QuadPart = (ULONGLONG)0;
00608     *BasePeb = NULL;
00609 
00610     //
00611     // Attach to Process
00612     //
00613     KeAttachProcess(&Process->Pcb);
00614 
00615     //
00616     // Map NLS Tables
00617     //
00618     Status = MmMapViewOfSection(ExpNlsSectionPointer,
00619                                 (PEPROCESS)Process,
00620                                 &TableBase,
00621                                 0,
00622                                 0,
00623                                 &SectionOffset,
00624                                 &ViewSize,
00625                                 ViewShare,
00626                                 MEM_TOP_DOWN,
00627                                 PAGE_READONLY);
00628     DPRINT("NLS Tables at: %p\n", TableBase);
00629     if (!NT_SUCCESS(Status))
00630     {
00631         /* Cleanup and exit */
00632         KeDetachProcess();
00633         return Status;
00634     }
00635 
00636     //
00637     // Allocate the PEB
00638     //
00639     Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb);
00640     DPRINT("PEB at: %p\n", Peb);
00641     if (!NT_SUCCESS(Status))
00642     {
00643         /* Cleanup and exit */
00644         KeDetachProcess();
00645         return Status;
00646     }
00647 
00648     //
00649     // Use SEH in case we can't load the PEB
00650     //
00651     _SEH2_TRY
00652     {
00653         //
00654         // Initialize the PEB
00655         //
00656         RtlZeroMemory(Peb, sizeof(PEB));
00657 
00658         //
00659         // Set up data
00660         //
00661         Peb->ImageBaseAddress = Process->SectionBaseAddress;
00662         Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace;
00663         Peb->Mutant = InitialPeb->Mutant;
00664         Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages;
00665 
00666         //
00667         // NLS
00668         //
00669         Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset;
00670         Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset;
00671         Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset;
00672 
00673         //
00674         // Default Version Data (could get changed below)
00675         //
00676         Peb->OSMajorVersion = NtMajorVersion;
00677         Peb->OSMinorVersion = NtMinorVersion;
00678         Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
00679         Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */
00680         Peb->OSCSDVersion = (USHORT)CmNtCSDVersion;
00681 
00682         //
00683         // Heap and Debug Data
00684         //
00685         Peb->NumberOfProcessors = KeNumberProcessors;
00686         Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL);
00687         Peb->NtGlobalFlag = NtGlobalFlag;
00688         /*Peb->HeapSegmentReserve = MmHeapSegmentReserve;
00689          Peb->HeapSegmentCommit = MmHeapSegmentCommit;
00690          Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
00691          Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
00692          Peb->CriticalSectionTimeout = MmCriticalSectionTimeout;
00693          Peb->MinimumStackCommit = MmMinimumStackCommitInBytes;
00694          */
00695         Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID);
00696         Peb->ProcessHeaps = (PVOID*)(Peb + 1);
00697 
00698         //
00699         // Session ID
00700         //
00701         if (Process->Session) Peb->SessionId = 0; // MmGetSessionId(Process);
00702     }
00703     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00704     {
00705         //
00706         // Fail
00707         //
00708         KeDetachProcess();
00709         _SEH2_YIELD(return _SEH2_GetExceptionCode());
00710     }
00711     _SEH2_END;
00712 
00713     //
00714     // Use SEH in case we can't load the image
00715     //
00716     _SEH2_TRY
00717     {
00718         //
00719         // Get NT Headers
00720         //
00721         NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
00722         Characteristics = NtHeaders->FileHeader.Characteristics;
00723     }
00724     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00725     {
00726         //
00727         // Fail
00728         //
00729         KeDetachProcess();
00730         _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
00731     }
00732     _SEH2_END;
00733 
00734     //
00735     // Parse the headers
00736     //
00737     if (NtHeaders)
00738     {
00739         //
00740         // Use SEH in case we can't load the headers
00741         //
00742         _SEH2_TRY
00743         {
00744             //
00745             // Get the Image Config Data too
00746             //
00747             ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
00748                                                            TRUE,
00749                                                            IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
00750                                                            (PULONG)&ViewSize);
00751             if (ImageConfigData)
00752             {
00753                 //
00754                 // Probe it
00755                 //
00756                 ProbeForRead(ImageConfigData,
00757                              sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
00758                              sizeof(ULONG));
00759             }
00760 
00761             //
00762             // Write subsystem data
00763             //
00764             Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem;
00765             Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion;
00766             Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion;
00767 
00768             //
00769             // Check for version data
00770             //
00771             if (NtHeaders->OptionalHeader.Win32VersionValue)
00772             {
00773                 //
00774                 // Extract values and write them
00775                 //
00776                 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF;
00777                 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
00778                 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF;
00779                 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2;
00780 
00781                 /* Process CSD version override */
00782                 if ((ImageConfigData) && (ImageConfigData->CSDVersion))
00783                 {
00784                     /* Take the value from the image configuration directory */
00785                     Peb->OSCSDVersion = ImageConfigData->CSDVersion;
00786                 }
00787             }
00788 
00789             /* Process optional process affinity mask override */
00790             if ((ImageConfigData) && (ImageConfigData->ProcessAffinityMask))
00791             {
00792                 /* Take the value from the image configuration directory */
00793                 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask;
00794             }
00795 
00796             //
00797             // Check if this is a UP image
00798             if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)
00799             {
00800                 //
00801                 // Force it to use CPU 0
00802                 //
00803                 /* FIXME: this should use the MmRotatingUniprocessorNumber */
00804                 Peb->ImageProcessAffinityMask = 0;
00805             }
00806             else
00807             {
00808                 //
00809                 // Whatever was configured
00810                 //
00811                 Peb->ImageProcessAffinityMask = ProcessAffinityMask;
00812             }
00813         }
00814         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00815         {
00816             //
00817             // Fail
00818             //
00819             KeDetachProcess();
00820             _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT);
00821         }
00822         _SEH2_END;
00823     }
00824 
00825     //
00826     // Detach from the Process
00827     //
00828     KeDetachProcess();
00829     *BasePeb = Peb;
00830     return STATUS_SUCCESS;
00831 }
00832 
00833 NTSTATUS
00834 NTAPI
00835 MmCreateTeb(IN PEPROCESS Process,
00836             IN PCLIENT_ID ClientId,
00837             IN PINITIAL_TEB InitialTeb,
00838             OUT PTEB *BaseTeb)
00839 {
00840     PTEB Teb;
00841     NTSTATUS Status = STATUS_SUCCESS;
00842     *BaseTeb = NULL;
00843 
00844     //
00845     // Attach to Target
00846     //
00847     KeAttachProcess(&Process->Pcb);
00848 
00849     //
00850     // Allocate the TEB
00851     //
00852     Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb);
00853     ASSERT(NT_SUCCESS(Status));
00854 
00855     //
00856     // Use SEH in case we can't load the TEB
00857     //
00858     _SEH2_TRY
00859     {
00860         //
00861         // Initialize the PEB
00862         //
00863         RtlZeroMemory(Teb, sizeof(TEB));
00864 
00865         //
00866         // Set TIB Data
00867         //
00868 #ifdef _M_AMD64
00869         Teb->NtTib.ExceptionList = NULL;
00870 #else
00871         Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
00872 #endif
00873         Teb->NtTib.Self = (PNT_TIB)Teb;
00874 
00875         //
00876         // Identify this as an OS/2 V3.0 ("Cruiser") TIB
00877         //
00878         Teb->NtTib.Version = 30 << 8;
00879 
00880         //
00881         // Set TEB Data
00882         //
00883         Teb->ClientId = *ClientId;
00884         Teb->RealClientId = *ClientId;
00885         Teb->ProcessEnvironmentBlock = Process->Peb;
00886         Teb->CurrentLocale = PsDefaultThreadLocaleId;
00887 
00888         //
00889         // Check if we have a grandparent TEB
00890         //
00891         if ((InitialTeb->PreviousStackBase == NULL) &&
00892             (InitialTeb->PreviousStackLimit == NULL))
00893         {
00894             //
00895             // Use initial TEB values
00896             //
00897             Teb->NtTib.StackBase = InitialTeb->StackBase;
00898             Teb->NtTib.StackLimit = InitialTeb->StackLimit;
00899             Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
00900         }
00901         else
00902         {
00903             //
00904             // Use grandparent TEB values
00905             //
00906             Teb->NtTib.StackBase = InitialTeb->PreviousStackBase;
00907             Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit;
00908         }
00909 
00910         //
00911         // Initialize the static unicode string
00912         //
00913         Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
00914         Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
00915     }
00916     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00917     {
00918         //
00919         // Get error code
00920         //
00921         Status = _SEH2_GetExceptionCode();
00922     }
00923     _SEH2_END;
00924 
00925     //
00926     // Return
00927     //
00928     KeDetachProcess();
00929     *BaseTeb = Teb;
00930     return Status;
00931 }
00932 
00933 VOID
00934 NTAPI
00935 MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
00936 {
00937     PMMPFN Pfn1;
00938     PMMPTE sysPte;
00939     MMPTE tempPte;
00940 
00941     /* Setup some bogus list data */
00942     MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
00943     MmWorkingSetList->HashTable = NULL;
00944     MmWorkingSetList->HashTableSize = 0;
00945     MmWorkingSetList->NumberOfImageWaiters = 0;
00946     MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
00947     MmWorkingSetList->VadBitMapHint = 1;
00948     MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
00949     MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
00950     MmWorkingSetList->FirstFree = 1;
00951     MmWorkingSetList->FirstDynamic = 2;
00952     MmWorkingSetList->NextSlot = 3;
00953     MmWorkingSetList->LastInitializedWsle = 4;
00954 
00955     /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */
00956     Pfn1 = MiGetPfnEntry(CurrentProcess->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT);
00957     ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
00958     Pfn1->u1.Event = (PKEVENT)CurrentProcess;
00959 
00960     /* Map the process working set in kernel space */
00961     sysPte = MiReserveSystemPtes(1, SystemPteSpace);
00962     MI_MAKE_HARDWARE_PTE_KERNEL(&tempPte, sysPte, MM_READWRITE, CurrentProcess->WorkingSetPage);
00963     MI_WRITE_VALID_PTE(sysPte, tempPte);
00964     CurrentProcess->Vm.VmWorkingSetList = MiPteToAddress(sysPte);
00965 }
00966 
00967 NTSTATUS
00968 NTAPI
00969 MmInitializeProcessAddressSpace(IN PEPROCESS Process,
00970                                 IN PEPROCESS ProcessClone OPTIONAL,
00971                                 IN PVOID Section OPTIONAL,
00972                                 IN OUT PULONG Flags,
00973                                 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL)
00974 {
00975     NTSTATUS Status = STATUS_SUCCESS;
00976     SIZE_T ViewSize = 0;
00977     PVOID ImageBase = 0;
00978     PROS_SECTION_OBJECT SectionObject = Section;
00979     PMMPTE PointerPte;
00980     KIRQL OldIrql;
00981     PMMPDE PointerPde;
00982     PFN_NUMBER PageFrameNumber;
00983     UNICODE_STRING FileName;
00984     PWCHAR Source;
00985     PCHAR Destination;
00986     USHORT Length = 0;
00987     MMPTE TempPte;
00988 
00989     /* We should have a PDE */
00990     ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
00991     ASSERT(Process->PdeUpdateNeeded == FALSE);
00992 
00993     /* Attach to the process */
00994     KeAttachProcess(&Process->Pcb);
00995 
00996     /* The address space should now been in phase 1 or 0 */
00997     ASSERT(Process->AddressSpaceInitialized <= 1);
00998     Process->AddressSpaceInitialized = 2;
00999 
01000     /* Initialize the Addresss Space lock */
01001     KeInitializeGuardedMutex(&Process->AddressCreationLock);
01002     Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
01003 
01004     /* Initialize AVL tree */
01005     ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
01006     Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
01007 
01008     /* Lock PFN database */
01009     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01010 
01011     /* Setup the PFN for the PDE base of this process */
01012 #ifdef _M_AMD64
01013     PointerPte = MiAddressToPte(PXE_BASE);
01014 #else
01015     PointerPte = MiAddressToPte(PDE_BASE);
01016 #endif
01017     PageFrameNumber = PFN_FROM_PTE(PointerPte);
01018     ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE);
01019     MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
01020 
01021     /* Do the same for hyperspace */
01022 #ifdef _M_AMD64
01023     PointerPde = MiAddressToPxe((PVOID)HYPER_SPACE);
01024 #else
01025     PointerPde = MiAddressToPde(HYPER_SPACE);
01026 #endif
01027     PageFrameNumber = PFN_FROM_PTE(PointerPde);
01028     //ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); // we're not lucky
01029     MiInitializePfn(PageFrameNumber, (PMMPTE)PointerPde, TRUE);
01030 
01031     /* Setup the PFN for the PTE for the working set */
01032     PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
01033     MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
01034     ASSERT(PointerPte->u.Long != 0);
01035     PageFrameNumber = PFN_FROM_PTE(PointerPte);
01036     MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
01037     MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
01038     TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
01039     MI_WRITE_VALID_PTE(PointerPte, TempPte);
01040 
01041     /* Now initialize the working set list */
01042     MiInitializeWorkingSetList(Process);
01043 
01044     /* Sanity check */
01045     ASSERT(Process->PhysicalVadRoot == NULL);
01046 
01047     /* Release PFN lock */
01048     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01049 
01050     /* Lock the VAD, ARM3-owned ranges away */
01051     MiRosTakeOverSharedUserPage(Process);
01052 
01053     /* Check if there's a Section Object */
01054     if (SectionObject)
01055     {
01056         /* Determine the image file name and save it to EPROCESS */
01057         FileName = SectionObject->FileObject->FileName;
01058         Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length);
01059         if (FileName.Buffer)
01060         {
01061             /* Loop the file name*/
01062             while (Source > FileName.Buffer)
01063             {
01064                 /* Make sure this isn't a backslash */
01065                 if (*--Source == OBJ_NAME_PATH_SEPARATOR)
01066                 {
01067                     /* If so, stop it here */
01068                     Source++;
01069                     break;
01070                 }
01071                 else
01072                 {
01073                     /* Otherwise, keep going */
01074                     Length++;
01075                 }
01076             }
01077         }
01078 
01079         /* Copy the to the process and truncate it to 15 characters if necessary */
01080         Destination = Process->ImageFileName;
01081         Length = min(Length, sizeof(Process->ImageFileName) - 1);
01082         while (Length--) *Destination++ = (UCHAR)*Source++;
01083         *Destination = ANSI_NULL;
01084 
01085         /* Check if caller wants an audit name */
01086         if (AuditName)
01087         {
01088             /* Setup the audit name */
01089             Status = SeInitializeProcessAuditName(SectionObject->FileObject,
01090                                                   FALSE,
01091                                                   AuditName);
01092             if (!NT_SUCCESS(Status))
01093             {
01094                 /* Fail */
01095                 KeDetachProcess();
01096                 return Status;
01097             }
01098         }
01099 
01100         /* Map the section */
01101         Status = MmMapViewOfSection(Section,
01102                                     Process,
01103                                     (PVOID*)&ImageBase,
01104                                     0,
01105                                     0,
01106                                     NULL,
01107                                     &ViewSize,
01108                                     0,
01109                                     MEM_COMMIT,
01110                                     PAGE_READWRITE);
01111 
01112         /* Save the pointer */
01113         Process->SectionBaseAddress = ImageBase;
01114     }
01115 
01116     /* Be nice and detach */
01117     KeDetachProcess();
01118 
01119     /* Return status to caller */
01120     return Status;
01121 }
01122 
01123 NTSTATUS
01124 NTAPI
01125 INIT_FUNCTION
01126 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
01127                              IN PULONG_PTR DirectoryTableBase)
01128 {
01129     /* Share the directory base with the idle process */
01130     DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0];
01131     DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1];
01132 
01133     /* Initialize the Addresss Space */
01134     KeInitializeGuardedMutex(&Process->AddressCreationLock);
01135     KeInitializeSpinLock(&Process->HyperSpaceLock);
01136     Process->Vm.WorkingSetExpansionLinks.Flink = NULL;
01137     ASSERT(Process->VadRoot.NumberGenericTableElements == 0);
01138     Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot;
01139 
01140     /* Use idle process Working set */
01141     Process->Vm.VmWorkingSetList = PsGetCurrentProcess()->Vm.VmWorkingSetList;
01142 
01143     /* Done */
01144     Process->HasAddressSpace = TRUE;//??
01145     return STATUS_SUCCESS;
01146 }
01147 
01148 NTSTATUS
01149 NTAPI
01150 INIT_FUNCTION
01151 MmInitializeHandBuiltProcess2(IN PEPROCESS Process)
01152 {
01153     /* Lock the VAD, ARM3-owned ranges away */
01154     MiRosTakeOverSharedUserPage(Process);
01155     return STATUS_SUCCESS;
01156 }
01157 
01158 #ifdef _M_IX86
01159 /* FIXME: Evaluate ways to make this portable yet arch-specific */
01160 BOOLEAN
01161 NTAPI
01162 MmCreateProcessAddressSpace(IN ULONG MinWs,
01163                             IN PEPROCESS Process,
01164                             OUT PULONG_PTR DirectoryTableBase)
01165 {
01166     KIRQL OldIrql;
01167     PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
01168     PMMPTE PointerPte;
01169     MMPTE TempPte, PdePte;
01170     ULONG PdeOffset;
01171     PMMPTE SystemTable, HyperTable;
01172     ULONG Color;
01173     PMMPFN Pfn1;
01174 
01175     /* Choose a process color */
01176     Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed);
01177 
01178     /* Setup the hyperspace lock */
01179     KeInitializeSpinLock(&Process->HyperSpaceLock);
01180 
01181     /* Lock PFN database */
01182     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01183 
01184     /* Get a zero page for the PDE, if possible */
01185     Color = MI_GET_NEXT_PROCESS_COLOR(Process);
01186     MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
01187     PdeIndex = MiRemoveZeroPageSafe(Color);
01188     if (!PdeIndex)
01189     {
01190         /* No zero pages, grab a free one */
01191         PdeIndex = MiRemoveAnyPage(Color);
01192 
01193         /* Zero it outside the PFN lock */
01194         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01195         MiZeroPhysicalPage(PdeIndex);
01196         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01197     }
01198 
01199     /* Get a zero page for hyperspace, if possible */
01200     MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY);
01201     Color = MI_GET_NEXT_PROCESS_COLOR(Process);
01202     HyperIndex = MiRemoveZeroPageSafe(Color);
01203     if (!HyperIndex)
01204     {
01205         /* No zero pages, grab a free one */
01206         HyperIndex = MiRemoveAnyPage(Color);
01207 
01208         /* Zero it outside the PFN lock */
01209         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01210         MiZeroPhysicalPage(HyperIndex);
01211         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01212     }
01213 
01214     /* Get a zero page for the woring set list, if possible */
01215     MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
01216     Color = MI_GET_NEXT_PROCESS_COLOR(Process);
01217     WsListIndex = MiRemoveZeroPageSafe(Color);
01218     if (!WsListIndex)
01219     {
01220         /* No zero pages, grab a free one */
01221         WsListIndex = MiRemoveAnyPage(Color);
01222 
01223         /* Zero it outside the PFN lock */
01224         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01225         MiZeroPhysicalPage(WsListIndex);
01226     }
01227     else
01228     {
01229         /* Release the PFN lock */
01230         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01231     }
01232 
01233     /* Switch to phase 1 initialization */
01234     ASSERT(Process->AddressSpaceInitialized == 0);
01235     Process->AddressSpaceInitialized = 1;
01236 
01237     /* Set the base directory pointers */
01238     Process->WorkingSetPage = WsListIndex;
01239     DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
01240     DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
01241 
01242     /* Make sure we don't already have a page directory setup */
01243     ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
01244 
01245     /* Get a PTE to map hyperspace */
01246     PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
01247     ASSERT(PointerPte != NULL);
01248 
01249     /* Build it */
01250     MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
01251                                 PointerPte,
01252                                 MM_READWRITE,
01253                                 HyperIndex);
01254 
01255     /* Set it dirty and map it */
01256     MI_MAKE_DIRTY_PAGE(&PdePte);
01257     MI_WRITE_VALID_PTE(PointerPte, PdePte);
01258 
01259     /* Now get hyperspace's page table */
01260     HyperTable = MiPteToAddress(PointerPte);
01261 
01262     /* Now write the PTE/PDE entry for the working set list index itself */
01263     TempPte = ValidKernelPte;
01264     TempPte.u.Hard.PageFrameNumber = WsListIndex;
01265     /* Hyperspace is local */
01266     MI_MAKE_LOCAL_PAGE(&TempPte);
01267     PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
01268     HyperTable[PdeOffset] = TempPte;
01269 
01270     /* Let go of the system PTE */
01271     MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
01272 
01273     /* Save the PTE address of the page directory itself */
01274     Pfn1 = MiGetPfnEntry(PdeIndex);
01275     Pfn1->PteAddress = (PMMPTE)PDE_BASE;
01276 
01277     /* Insert us into the Mm process list */
01278     InsertTailList(&MmProcessList, &Process->MmProcessLinks);
01279 
01280     /* Get a PTE to map the page directory */
01281     PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
01282     ASSERT(PointerPte != NULL);
01283 
01284     /* Build it */
01285     MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
01286                                 PointerPte,
01287                                 MM_READWRITE,
01288                                 PdeIndex);
01289 
01290     /* Set it dirty and map it */
01291     MI_MAKE_DIRTY_PAGE(&PdePte);
01292     MI_WRITE_VALID_PTE(PointerPte, PdePte);
01293 
01294     /* Now get the page directory (which we'll double map, so call it a page table */
01295     SystemTable = MiPteToAddress(PointerPte);
01296 
01297     /* Copy all the kernel mappings */
01298     PdeOffset = MiGetPdeOffset(MmSystemRangeStart);
01299     RtlCopyMemory(&SystemTable[PdeOffset],
01300                   MiAddressToPde(MmSystemRangeStart),
01301                   PAGE_SIZE - PdeOffset * sizeof(MMPTE));
01302 
01303     /* Now write the PTE/PDE entry for hyperspace itself */
01304     TempPte = ValidKernelPte;
01305     TempPte.u.Hard.PageFrameNumber = HyperIndex;
01306     PdeOffset = MiGetPdeOffset(HYPER_SPACE);
01307     SystemTable[PdeOffset] = TempPte;
01308 
01309     /* Sanity check */
01310     PdeOffset++;
01311     ASSERT(MiGetPdeOffset(MmHyperSpaceEnd) >= PdeOffset);
01312 
01313     /* Now do the x86 trick of making the PDE a page table itself */
01314     PdeOffset = MiGetPdeOffset(PTE_BASE);
01315     TempPte.u.Hard.PageFrameNumber = PdeIndex;
01316     SystemTable[PdeOffset] = TempPte;
01317 
01318     /* Let go of the system PTE */
01319     MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
01320     return TRUE;
01321 }
01322 #endif
01323 
01324 VOID
01325 NTAPI
01326 MmCleanProcessAddressSpace(IN PEPROCESS Process)
01327 {
01328     PMMVAD Vad;
01329     PMM_AVL_TABLE VadTree;
01330     PETHREAD Thread = PsGetCurrentThread();
01331 
01332     /* Only support this */
01333     ASSERT(Process->AddressSpaceInitialized == 2);
01334 
01335     /* Lock the process address space from changes */
01336     MmLockAddressSpace(&Process->Vm);
01337 
01338     /* VM is deleted now */
01339     Process->VmDeleted = TRUE;
01340 
01341     /* Enumerate the VADs */
01342     VadTree = &Process->VadRoot;
01343     while (VadTree->NumberGenericTableElements)
01344     {
01345         /* Grab the current VAD */
01346         Vad = (PMMVAD)VadTree->BalancedRoot.RightChild;
01347 
01348         /* Lock the working set */
01349         MiLockProcessWorkingSet(Process, Thread);
01350 
01351         /* Remove this VAD from the tree */
01352         ASSERT(VadTree->NumberGenericTableElements >= 1);
01353         MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
01354 
01355         /* Only regular VADs supported for now */
01356         ASSERT(Vad->u.VadFlags.VadType == VadNone);
01357 
01358         /* Check if this is a section VAD */
01359         if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
01360         {
01361             /* Remove the view */
01362             MiRemoveMappedView(Process, Vad);
01363         }
01364         else
01365         {
01366             /* Delete the addresses */
01367             MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
01368                                      (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
01369                                      Vad);
01370 
01371             /* Release the working set */
01372             MiUnlockProcessWorkingSet(Process, Thread);
01373         }
01374 
01375         /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
01376         if (Vad->u.VadFlags.Spare == 1)
01377         {
01378             /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */
01379             Vad->u.VadFlags.Spare = 2;
01380             continue;
01381         }
01382 
01383         /* Free the VAD memory */
01384         ExFreePool(Vad);
01385     }
01386     /* Delete the shared user data section */
01387     MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL);
01388 
01389     /* Release the address space */
01390     MmUnlockAddressSpace(&Process->Vm);
01391 }
01392 
01393 VOID
01394 NTAPI
01395 MmDeleteProcessAddressSpace2(IN PEPROCESS Process)
01396 {
01397     PMMPFN Pfn1, Pfn2;
01398     KIRQL OldIrql;
01399     PFN_NUMBER PageFrameIndex;
01400 
01401     //ASSERT(Process->CommitCharge == 0);
01402 
01403     /* Acquire the PFN lock */
01404     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01405 
01406     /* Check for fully initialized process */
01407     if (Process->AddressSpaceInitialized == 2)
01408     {
01409         /* Map the working set page and its page table */
01410         Pfn1 = MiGetPfnEntry(Process->WorkingSetPage);
01411         Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
01412 
01413         /* Nuke it */
01414         MI_SET_PFN_DELETED(Pfn1);
01415         MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
01416         MiDecrementShareCount(Pfn1, Process->WorkingSetPage);
01417         ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
01418         MiReleaseSystemPtes(MiAddressToPte(Process->Vm.VmWorkingSetList), 1, SystemPteSpace);
01419 
01420         /* Now map hyperspace and its page table */
01421         PageFrameIndex = Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT;
01422         Pfn1 = MiGetPfnEntry(PageFrameIndex);
01423         Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
01424 
01425         /* Nuke it */
01426         MI_SET_PFN_DELETED(Pfn1);
01427         MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
01428         MiDecrementShareCount(Pfn1, PageFrameIndex);
01429         ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
01430 
01431         /* Finally, nuke the PDE itself */
01432         PageFrameIndex = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT;
01433         Pfn1 = MiGetPfnEntry(PageFrameIndex);
01434         MI_SET_PFN_DELETED(Pfn1);
01435         MiDecrementShareCount(Pfn1, PageFrameIndex);
01436         MiDecrementShareCount(Pfn1, PageFrameIndex);
01437 
01438         /* Page table is now dead. Bye bye... */
01439         ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress));
01440     }
01441     else
01442     {
01443         /* A partly-initialized process should never exit through here */
01444         ASSERT(FALSE);
01445     }
01446 
01447     /* Release the PFN lock */
01448     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01449 
01450     /* No support for sessions yet */
01451     ASSERT(Process->Session == 0);
01452 
01453     /* Clear out the PDE pages */
01454     Process->Pcb.DirectoryTableBase[0] = 0;
01455     Process->Pcb.DirectoryTableBase[1] = 0;
01456 }
01457 
01458 /* SESSION CODE TO MOVE TO SESSION.C ******************************************/
01459 
01460 KGUARDED_MUTEX MiSessionIdMutex;
01461 PRTL_BITMAP MiSessionIdBitmap;
01462 volatile LONG MiSessionLeaderExists;
01463 
01464 VOID
01465 NTAPI
01466 MiInitializeSessionIds(VOID)
01467 {
01468     /* FIXME: Other stuff should go here */
01469 
01470     /* Initialize the lock */
01471     KeInitializeGuardedMutex(&MiSessionIdMutex);
01472 
01473     /* Allocate the bitmap */
01474     MiSessionIdBitmap = ExAllocatePoolWithTag(PagedPool,
01475                                               sizeof(RTL_BITMAP) + ((64 + 31) / 32) * 4,
01476                                               '  mM');
01477     if (MiSessionIdBitmap)
01478     {
01479         /* Free all the bits */
01480         RtlInitializeBitMap(MiSessionIdBitmap, (PVOID)(MiSessionIdBitmap + 1), 64);
01481         RtlClearAllBits(MiSessionIdBitmap);
01482     }
01483     else
01484     {
01485         /* Die if we couldn't allocate the bitmap */
01486         KeBugCheckEx(INSTALL_MORE_MEMORY,
01487                      MmNumberOfPhysicalPages,
01488                      MmLowestPhysicalPage,
01489                      MmHighestPhysicalPage,
01490                      0x200);
01491     }
01492 }
01493 
01494 VOID
01495 NTAPI
01496 MiSessionLeader(IN PEPROCESS Process)
01497 {
01498     KIRQL OldIrql;
01499 
01500     /* Set the flag while under the expansion lock */
01501     OldIrql = KeAcquireQueuedSpinLock(LockQueueExpansionLock);
01502     Process->Vm.Flags.SessionLeader = TRUE;
01503     KeReleaseQueuedSpinLock(LockQueueExpansionLock, OldIrql);
01504 }
01505 
01506 NTSTATUS
01507 NTAPI
01508 MiSessionCreateInternal(OUT PULONG SessionId)
01509 {
01510     PEPROCESS Process = PsGetCurrentProcess();
01511     ULONG NewFlags, Flags;
01512 
01513     /* Loop so we can set the session-is-creating flag */
01514     Flags = Process->Flags;
01515     while (TRUE)
01516     {
01517         /* Check if it's already set */
01518         if (Flags & PSF_SESSION_CREATION_UNDERWAY_BIT)
01519         {
01520             /* Bail out */
01521             DPRINT1("Lost session race\n");
01522             return STATUS_ALREADY_COMMITTED;
01523         }
01524 
01525         /* Now try to set it */
01526         NewFlags = InterlockedCompareExchange((PLONG)&Process->Flags,
01527                                               Flags | PSF_SESSION_CREATION_UNDERWAY_BIT,
01528                                               Flags);
01529         if (NewFlags == Flags) break;
01530 
01531         /* It changed, try again */
01532         Flags = NewFlags;
01533     }
01534 
01535     /* Now we should own the flag */
01536     ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
01537 
01538     /* Allocate a new Session ID */
01539     KeAcquireGuardedMutex(&MiSessionIdMutex);
01540     *SessionId = RtlFindClearBitsAndSet(MiSessionIdBitmap, 1, 0);
01541     if (*SessionId == 0xFFFFFFFF)
01542     {
01543         DPRINT1("Too many sessions created. Expansion not yet supported\n");
01544         return STATUS_NO_MEMORY;
01545     }
01546     KeReleaseGuardedMutex(&MiSessionIdMutex);
01547 
01548     /* We're done, clear the flag */
01549     ASSERT(Process->Flags & PSF_SESSION_CREATION_UNDERWAY_BIT);
01550     PspClearProcessFlag(Process, PSF_SESSION_CREATION_UNDERWAY_BIT);
01551     return STATUS_SUCCESS;
01552 }
01553 
01554 NTSTATUS
01555 NTAPI
01556 MmSessionCreate(OUT PULONG SessionId)
01557 {
01558     PEPROCESS Process = PsGetCurrentProcess();
01559     ULONG SessionLeaderExists;
01560     NTSTATUS Status;
01561 
01562     /* Fail if the process is already in a session */
01563     if (Process->Flags & PSF_PROCESS_IN_SESSION_BIT)
01564     {
01565         DPRINT1("Process already in session\n");
01566         return STATUS_ALREADY_COMMITTED;
01567     }
01568 
01569     /* Check if the process is already the session leader */
01570     if (!Process->Vm.Flags.SessionLeader)
01571     {
01572         /* Atomically set it as the leader */
01573         SessionLeaderExists = InterlockedCompareExchange(&MiSessionLeaderExists, 1, 0);
01574         if (SessionLeaderExists)
01575         {
01576             DPRINT1("Session leader race\n");
01577             return STATUS_INVALID_SYSTEM_SERVICE;
01578         }
01579 
01580         /* Do the work required to upgrade him */
01581         MiSessionLeader(Process);
01582     }
01583 
01584     /* FIXME: Actually create a session */
01585     KeEnterCriticalRegion();
01586     Status = MiSessionCreateInternal(SessionId);
01587     KeLeaveCriticalRegion();
01588 
01589     /* Set and assert the flags, and return */
01590     PspSetProcessFlag(Process, PSF_PROCESS_IN_SESSION_BIT);
01591     ASSERT(MiSessionLeaderExists == 1);
01592     return Status;
01593 }
01594 
01595 NTSTATUS
01596 NTAPI
01597 MmSessionDelete(IN ULONG SessionId)
01598 {
01599     PEPROCESS Process = PsGetCurrentProcess();
01600 
01601     /* Process must be in a session */
01602     if (!(Process->Flags & PSF_PROCESS_IN_SESSION_BIT))
01603     {
01604         DPRINT1("Not in a session!\n");
01605         return STATUS_UNABLE_TO_FREE_VM;
01606     }
01607 
01608     /* It must be the session leader */
01609     if (!Process->Vm.Flags.SessionLeader)
01610     {
01611         DPRINT1("Not a session leader!\n");
01612         return STATUS_UNABLE_TO_FREE_VM;
01613     }
01614 
01615     /* Remove one reference count */
01616     KeEnterCriticalRegion();
01617     /* FIXME: Do it */
01618     KeLeaveCriticalRegion();
01619 
01620     /* All done */
01621     return STATUS_SUCCESS;
01622 }
01623 
01624 /* SYSTEM CALLS ***************************************************************/
01625 
01626 NTSTATUS
01627 NTAPI
01628 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle,
01629                             IN OUT PULONG_PTR NumberOfPages,
01630                             IN OUT PULONG_PTR UserPfnArray)
01631 {
01632     UNIMPLEMENTED;
01633     return STATUS_NOT_IMPLEMENTED;
01634 }
01635 
01636 NTSTATUS
01637 NTAPI
01638 NtMapUserPhysicalPages(IN PVOID VirtualAddresses,
01639                        IN ULONG_PTR NumberOfPages,
01640                        IN OUT PULONG_PTR UserPfnArray)
01641 {
01642     UNIMPLEMENTED;
01643     return STATUS_NOT_IMPLEMENTED;
01644 }
01645 
01646 NTSTATUS
01647 NTAPI
01648 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses,
01649                               IN ULONG_PTR NumberOfPages,
01650                               IN OUT PULONG_PTR UserPfnArray)
01651 {
01652     UNIMPLEMENTED;
01653     return STATUS_NOT_IMPLEMENTED;
01654 }
01655 
01656 NTSTATUS
01657 NTAPI
01658 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle,
01659                         IN OUT PULONG_PTR NumberOfPages,
01660                         IN OUT PULONG_PTR UserPfnArray)
01661 {
01662     UNIMPLEMENTED;
01663     return STATUS_NOT_IMPLEMENTED;
01664 }
01665 
01666 /* EOF */

Generated on Sun May 27 2012 04:37:35 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.