Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenprocsup.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
1.7.6.1
|