1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/procsup.c 5 * PURPOSE: ARM Memory Manager Process Related Management 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #define MODULE_INVOLVED_IN_ARM3 16 #include <mm/ARM3/miarm.h> 17 18 /* GLOBALS ********************************************************************/ 19 20 ULONG MmProcessColorSeed = 0x12345678; 21 ULONG MmMaximumDeadKernelStacks = 5; 22 SLIST_HEADER MmDeadStackSListHead; 23 24 /* PRIVATE FUNCTIONS **********************************************************/ 25 26 NTSTATUS 27 NTAPI 28 MiCreatePebOrTeb(IN PEPROCESS Process, 29 IN ULONG Size, 30 OUT PULONG_PTR BaseAddress) 31 { 32 PMMVAD_LONG Vad; 33 NTSTATUS Status; 34 ULONG_PTR HighestAddress, RandomBase; 35 ULONG AlignedSize; 36 LARGE_INTEGER CurrentTime; 37 38 Status = PsChargeProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG)); 39 if (!NT_SUCCESS(Status)) 40 return Status; 41 42 /* Allocate a VAD */ 43 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV'); 44 if (!Vad) 45 { 46 Status = STATUS_NO_MEMORY; 47 goto FailPath; 48 } 49 50 /* Setup the primary flags with the size, and make it commited, private, RW */ 51 Vad->u.LongFlags = 0; 52 Vad->u.VadFlags.CommitCharge = BYTES_TO_PAGES(Size); 53 Vad->u.VadFlags.MemCommit = TRUE; 54 Vad->u.VadFlags.PrivateMemory = TRUE; 55 Vad->u.VadFlags.Protection = MM_READWRITE; 56 Vad->u.VadFlags.NoChange = TRUE; 57 Vad->u1.Parent = NULL; 58 59 /* Setup the secondary flags to make it a secured, writable, long VAD */ 60 Vad->u2.LongFlags2 = 0; 61 Vad->u2.VadFlags2.OneSecured = TRUE; 62 Vad->u2.VadFlags2.LongVad = TRUE; 63 Vad->u2.VadFlags2.ReadOnly = FALSE; 64 65 Vad->ControlArea = NULL; // For Memory-Area hack 66 Vad->FirstPrototypePte = NULL; 67 68 /* Check if this is a PEB creation */ 69 ASSERT(sizeof(TEB) != sizeof(PEB)); 70 if (Size == sizeof(PEB)) 71 { 72 /* Create a random value to select one page in a 64k region */ 73 KeQueryTickCount(&CurrentTime); 74 CurrentTime.LowPart &= (_64K / PAGE_SIZE) - 1; 75 76 /* Calculate a random base address */ 77 RandomBase = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1; 78 RandomBase -= CurrentTime.LowPart << PAGE_SHIFT; 79 80 /* Make sure the base address is not too high */ 81 AlignedSize = ROUND_TO_PAGES(Size); 82 if ((RandomBase + AlignedSize) > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) 83 { 84 RandomBase = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1 - AlignedSize; 85 } 86 87 /* Calculate the highest allowed address */ 88 HighestAddress = RandomBase + AlignedSize - 1; 89 } 90 else 91 { 92 HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS; 93 } 94 95 *BaseAddress = 0; 96 Status = MiInsertVadEx((PMMVAD)Vad, 97 BaseAddress, 98 Size, 99 HighestAddress, 100 PAGE_SIZE, 101 MEM_TOP_DOWN); 102 if (!NT_SUCCESS(Status)) 103 { 104 ExFreePoolWithTag(Vad, 'ldaV'); 105 Status = STATUS_NO_MEMORY; 106 goto FailPath; 107 } 108 109 110 /* Success */ 111 return STATUS_SUCCESS; 112 113 FailPath: 114 PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG)); 115 116 return Status; 117 } 118 119 VOID 120 NTAPI 121 MmDeleteTeb(IN PEPROCESS Process, 122 IN PTEB Teb) 123 { 124 ULONG_PTR TebEnd; 125 PETHREAD Thread = PsGetCurrentThread(); 126 PMMVAD Vad; 127 PMM_AVL_TABLE VadTree = &Process->VadRoot; 128 DPRINT("Deleting TEB: %p in %16s\n", Teb, Process->ImageFileName); 129 130 /* TEB is one page */ 131 TebEnd = (ULONG_PTR)Teb + ROUND_TO_PAGES(sizeof(TEB)) - 1; 132 133 /* Attach to the process */ 134 KeAttachProcess(&Process->Pcb); 135 136 /* Lock the process address space */ 137 KeAcquireGuardedMutex(&Process->AddressCreationLock); 138 139 /* Find the VAD, make sure it's a TEB VAD */ 140 Vad = MiLocateAddress(Teb); 141 DPRINT("Removing node for VAD: %lx %lx\n", Vad->StartingVpn, Vad->EndingVpn); 142 ASSERT(Vad != NULL); 143 if (Vad->StartingVpn != ((ULONG_PTR)Teb >> PAGE_SHIFT)) 144 { 145 /* Bug in the AVL code? */ 146 DPRINT1("Corrupted VAD!\n"); 147 } 148 else 149 { 150 /* Sanity checks for a valid TEB VAD */ 151 ASSERT((Vad->StartingVpn == ((ULONG_PTR)Teb >> PAGE_SHIFT) && 152 (Vad->EndingVpn == (TebEnd >> PAGE_SHIFT)))); 153 ASSERT(Vad->u.VadFlags.NoChange == TRUE); 154 ASSERT(Vad->u2.VadFlags2.OneSecured == TRUE); 155 ASSERT(Vad->u2.VadFlags2.MultipleSecured == FALSE); 156 157 /* Lock the working set */ 158 MiLockProcessWorkingSetUnsafe(Process, Thread); 159 160 /* Remove this VAD from the tree */ 161 ASSERT(VadTree->NumberGenericTableElements >= 1); 162 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree); 163 164 /* Delete the pages */ 165 MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL); 166 167 /* Release the working set */ 168 MiUnlockProcessWorkingSetUnsafe(Process, Thread); 169 170 /* Remove the VAD */ 171 ExFreePool(Vad); 172 173 /* Return the quota the VAD used */ 174 PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG)); 175 } 176 177 /* Release the address space lock */ 178 KeReleaseGuardedMutex(&Process->AddressCreationLock); 179 180 /* Detach */ 181 KeDetachProcess(); 182 } 183 184 VOID 185 NTAPI 186 MmDeleteKernelStack(IN PVOID StackBase, 187 IN BOOLEAN GuiStack) 188 { 189 PMMPTE PointerPte; 190 PFN_NUMBER PageFrameNumber, PageTableFrameNumber; 191 PFN_COUNT StackPages; 192 PMMPFN Pfn1, Pfn2; 193 ULONG i; 194 KIRQL OldIrql; 195 PSLIST_ENTRY SListEntry; 196 197 // 198 // This should be the guard page, so decrement by one 199 // 200 PointerPte = MiAddressToPte(StackBase); 201 PointerPte--; 202 203 // 204 // If this is a small stack, just push the stack onto the dead stack S-LIST 205 // 206 if (!GuiStack) 207 { 208 if (ExQueryDepthSList(&MmDeadStackSListHead) < MmMaximumDeadKernelStacks) 209 { 210 SListEntry = ((PSLIST_ENTRY)StackBase) - 1; 211 InterlockedPushEntrySList(&MmDeadStackSListHead, SListEntry); 212 return; 213 } 214 } 215 216 // 217 // Calculate pages used 218 // 219 StackPages = BYTES_TO_PAGES(GuiStack ? 220 MmLargeStackSize : KERNEL_STACK_SIZE); 221 222 /* Acquire the PFN lock */ 223 OldIrql = MiAcquirePfnLock(); 224 225 // 226 // Loop them 227 // 228 for (i = 0; i < StackPages; i++) 229 { 230 // 231 // Check if this is a valid PTE 232 // 233 if (PointerPte->u.Hard.Valid == 1) 234 { 235 /* Get the PTE's page */ 236 PageFrameNumber = PFN_FROM_PTE(PointerPte); 237 Pfn1 = MiGetPfnEntry(PageFrameNumber); 238 239 /* Now get the page of the page table mapping it */ 240 PageTableFrameNumber = Pfn1->u4.PteFrame; 241 Pfn2 = MiGetPfnEntry(PageTableFrameNumber); 242 243 /* Remove a shared reference, since the page is going away */ 244 MiDecrementShareCount(Pfn2, PageTableFrameNumber); 245 246 /* Set the special pending delete marker */ 247 MI_SET_PFN_DELETED(Pfn1); 248 249 /* And now delete the actual stack page */ 250 MiDecrementShareCount(Pfn1, PageFrameNumber); 251 } 252 253 // 254 // Next one 255 // 256 PointerPte--; 257 } 258 259 // 260 // We should be at the guard page now 261 // 262 ASSERT(PointerPte->u.Hard.Valid == 0); 263 264 /* Release the PFN lock */ 265 MiReleasePfnLock(OldIrql); 266 267 // 268 // Release the PTEs 269 // 270 MiReleaseSystemPtes(PointerPte, StackPages + 1, SystemPteSpace); 271 } 272 273 PVOID 274 NTAPI 275 MmCreateKernelStack(IN BOOLEAN GuiStack, 276 IN UCHAR Node) 277 { 278 PFN_COUNT StackPtes, StackPages; 279 PMMPTE PointerPte, StackPte; 280 PVOID BaseAddress; 281 MMPTE TempPte, InvalidPte; 282 KIRQL OldIrql; 283 PFN_NUMBER PageFrameIndex; 284 ULONG i; 285 PSLIST_ENTRY SListEntry; 286 287 // 288 // Calculate pages needed 289 // 290 if (GuiStack) 291 { 292 // 293 // We'll allocate 64KB stack, but only commit 12K 294 // 295 StackPtes = BYTES_TO_PAGES(MmLargeStackSize); 296 StackPages = BYTES_TO_PAGES(KERNEL_LARGE_STACK_COMMIT); 297 } 298 else 299 { 300 // 301 // If the dead stack S-LIST has a stack on it, use it instead of allocating 302 // new system PTEs for this stack 303 // 304 if (ExQueryDepthSList(&MmDeadStackSListHead)) 305 { 306 SListEntry = InterlockedPopEntrySList(&MmDeadStackSListHead); 307 if (SListEntry != NULL) 308 { 309 BaseAddress = (SListEntry + 1); 310 return BaseAddress; 311 } 312 } 313 314 // 315 // We'll allocate 12K and that's it 316 // 317 StackPtes = BYTES_TO_PAGES(KERNEL_STACK_SIZE); 318 StackPages = StackPtes; 319 } 320 321 // 322 // Reserve stack pages, plus a guard page 323 // 324 StackPte = MiReserveSystemPtes(StackPtes + 1, SystemPteSpace); 325 if (!StackPte) return NULL; 326 327 // 328 // Get the stack address 329 // 330 BaseAddress = MiPteToAddress(StackPte + StackPtes + 1); 331 332 // 333 // Select the right PTE address where we actually start committing pages 334 // 335 PointerPte = StackPte; 336 if (GuiStack) PointerPte += BYTES_TO_PAGES(MmLargeStackSize - 337 KERNEL_LARGE_STACK_COMMIT); 338 339 340 /* Setup the temporary invalid PTE */ 341 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS); 342 343 /* Setup the template stack PTE */ 344 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0); 345 346 // 347 // Acquire the PFN DB lock 348 // 349 OldIrql = MiAcquirePfnLock(); 350 351 // 352 // Loop each stack page 353 // 354 for (i = 0; i < StackPages; i++) 355 { 356 // 357 // Next PTE 358 // 359 PointerPte++; 360 361 /* Get a page and write the current invalid PTE */ 362 MI_SET_USAGE(MI_USAGE_KERNEL_STACK); 363 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); 364 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 365 MI_WRITE_INVALID_PTE(PointerPte, InvalidPte); 366 367 /* Initialize the PFN entry for this page */ 368 MiInitializePfn(PageFrameIndex, PointerPte, 1); 369 370 /* Write the valid PTE */ 371 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 372 MI_WRITE_VALID_PTE(PointerPte, TempPte); 373 } 374 375 // 376 // Release the PFN lock 377 // 378 MiReleasePfnLock(OldIrql); 379 380 // 381 // Return the stack address 382 // 383 return BaseAddress; 384 } 385 386 NTSTATUS 387 NTAPI 388 MmGrowKernelStackEx(IN PVOID StackPointer, 389 IN ULONG GrowSize) 390 { 391 PKTHREAD Thread = KeGetCurrentThread(); 392 PMMPTE LimitPte, NewLimitPte, LastPte; 393 KIRQL OldIrql; 394 MMPTE TempPte, InvalidPte; 395 PFN_NUMBER PageFrameIndex; 396 397 // 398 // Make sure the stack did not overflow 399 // 400 ASSERT(((ULONG_PTR)Thread->StackBase - (ULONG_PTR)Thread->StackLimit) <= 401 (MmLargeStackSize + PAGE_SIZE)); 402 403 // 404 // Get the current stack limit 405 // 406 LimitPte = MiAddressToPte(Thread->StackLimit); 407 ASSERT(LimitPte->u.Hard.Valid == 1); 408 409 // 410 // Get the new one and make sure this isn't a retarded request 411 // 412 NewLimitPte = MiAddressToPte((PVOID)((ULONG_PTR)StackPointer - GrowSize)); 413 if (NewLimitPte == LimitPte) return STATUS_SUCCESS; 414 415 // 416 // Now make sure you're not going past the reserved space 417 // 418 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)Thread->StackBase - 419 MmLargeStackSize)); 420 if (NewLimitPte < LastPte) 421 { 422 // 423 // Sorry! 424 // 425 return STATUS_STACK_OVERFLOW; 426 } 427 428 // 429 // Calculate the number of new pages 430 // 431 LimitPte--; 432 433 /* Setup the temporary invalid PTE */ 434 MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS); 435 436 // 437 // Acquire the PFN DB lock 438 // 439 OldIrql = MiAcquirePfnLock(); 440 441 // 442 // Loop each stack page 443 // 444 while (LimitPte >= NewLimitPte) 445 { 446 /* Get a page and write the current invalid PTE */ 447 MI_SET_USAGE(MI_USAGE_KERNEL_STACK_EXPANSION); 448 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); 449 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 450 MI_WRITE_INVALID_PTE(LimitPte, InvalidPte); 451 452 /* Initialize the PFN entry for this page */ 453 MiInitializePfn(PageFrameIndex, LimitPte, 1); 454 455 /* Setup the template stack PTE */ 456 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex); 457 458 /* Write the valid PTE */ 459 MI_WRITE_VALID_PTE(LimitPte--, TempPte); 460 } 461 462 // 463 // Release the PFN lock 464 // 465 MiReleasePfnLock(OldIrql); 466 467 // 468 // Set the new limit 469 // 470 Thread->StackLimit = (ULONG_PTR)MiPteToAddress(NewLimitPte); 471 return STATUS_SUCCESS; 472 } 473 474 NTSTATUS 475 NTAPI 476 MmGrowKernelStack(IN PVOID StackPointer) 477 { 478 // 479 // Call the extended version 480 // 481 return MmGrowKernelStackEx(StackPointer, KERNEL_LARGE_STACK_COMMIT); 482 } 483 484 NTSTATUS 485 NTAPI 486 MmSetMemoryPriorityProcess(IN PEPROCESS Process, 487 IN UCHAR MemoryPriority) 488 { 489 UCHAR OldPriority; 490 491 // 492 // Check if we have less then 16MB of Physical Memory 493 // 494 if ((MmSystemSize == MmSmallSystem) && 495 (MmNumberOfPhysicalPages < ((15 * 1024 * 1024) / PAGE_SIZE))) 496 { 497 // 498 // Always use background priority 499 // 500 MemoryPriority = MEMORY_PRIORITY_BACKGROUND; 501 } 502 503 // 504 // Save the old priority and update it 505 // 506 OldPriority = (UCHAR)Process->Vm.Flags.MemoryPriority; 507 Process->Vm.Flags.MemoryPriority = MemoryPriority; 508 509 // 510 // Return the old priority 511 // 512 return OldPriority; 513 } 514 515 NTSTATUS 516 NTAPI 517 MmCreatePeb(IN PEPROCESS Process, 518 IN PINITIAL_PEB InitialPeb, 519 OUT PPEB *BasePeb) 520 { 521 PPEB Peb = NULL; 522 LARGE_INTEGER SectionOffset; 523 SIZE_T ViewSize = 0; 524 PVOID TableBase = NULL; 525 PIMAGE_NT_HEADERS NtHeaders; 526 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; 527 NTSTATUS Status; 528 USHORT Characteristics; 529 KAFFINITY ProcessAffinityMask = 0; 530 SectionOffset.QuadPart = (ULONGLONG)0; 531 *BasePeb = NULL; 532 533 // 534 // Attach to Process 535 // 536 KeAttachProcess(&Process->Pcb); 537 538 // 539 // Map NLS Tables 540 // 541 Status = MmMapViewOfSection(ExpNlsSectionPointer, 542 (PEPROCESS)Process, 543 &TableBase, 544 0, 545 0, 546 &SectionOffset, 547 &ViewSize, 548 ViewShare, 549 MEM_TOP_DOWN, 550 PAGE_READONLY); 551 DPRINT("NLS Tables at: %p\n", TableBase); 552 if (!NT_SUCCESS(Status)) 553 { 554 /* Cleanup and exit */ 555 KeDetachProcess(); 556 return Status; 557 } 558 559 // 560 // Allocate the PEB 561 // 562 Status = MiCreatePebOrTeb(Process, sizeof(PEB), (PULONG_PTR)&Peb); 563 DPRINT("PEB at: %p\n", Peb); 564 if (!NT_SUCCESS(Status)) 565 { 566 /* Cleanup and exit */ 567 KeDetachProcess(); 568 return Status; 569 } 570 571 // 572 // Use SEH in case we can't load the PEB 573 // 574 _SEH2_TRY 575 { 576 // 577 // Initialize the PEB 578 // 579 RtlZeroMemory(Peb, sizeof(PEB)); 580 581 // 582 // Set up data 583 // 584 Peb->ImageBaseAddress = Process->SectionBaseAddress; 585 Peb->InheritedAddressSpace = InitialPeb->InheritedAddressSpace; 586 Peb->Mutant = InitialPeb->Mutant; 587 Peb->ImageUsesLargePages = InitialPeb->ImageUsesLargePages; 588 589 // 590 // NLS 591 // 592 Peb->AnsiCodePageData = (PCHAR)TableBase + ExpAnsiCodePageDataOffset; 593 Peb->OemCodePageData = (PCHAR)TableBase + ExpOemCodePageDataOffset; 594 Peb->UnicodeCaseTableData = (PCHAR)TableBase + ExpUnicodeCaseTableDataOffset; 595 596 // 597 // Default Version Data (could get changed below) 598 // 599 Peb->OSMajorVersion = NtMajorVersion; 600 Peb->OSMinorVersion = NtMinorVersion; 601 Peb->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF); 602 Peb->OSPlatformId = VER_PLATFORM_WIN32_NT; 603 Peb->OSCSDVersion = (USHORT)CmNtCSDVersion; 604 605 // 606 // Heap and Debug Data 607 // 608 Peb->NumberOfProcessors = KeNumberProcessors; 609 Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL); 610 Peb->NtGlobalFlag = NtGlobalFlag; 611 Peb->HeapSegmentReserve = MmHeapSegmentReserve; 612 Peb->HeapSegmentCommit = MmHeapSegmentCommit; 613 Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold; 614 Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold; 615 Peb->CriticalSectionTimeout = MmCriticalSectionTimeout; 616 Peb->MinimumStackCommit = MmMinimumStackCommitInBytes; 617 Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID); 618 Peb->ProcessHeaps = (PVOID*)(Peb + 1); 619 620 // 621 // Session ID 622 // 623 if (Process->Session) Peb->SessionId = MmGetSessionId(Process); 624 } 625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 626 { 627 // 628 // Fail 629 // 630 KeDetachProcess(); 631 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 632 } 633 _SEH2_END; 634 635 // 636 // Use SEH in case we can't load the image 637 // 638 _SEH2_TRY 639 { 640 // 641 // Get NT Headers 642 // 643 NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress); 644 Characteristics = NtHeaders->FileHeader.Characteristics; 645 } 646 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 647 { 648 // 649 // Fail 650 // 651 KeDetachProcess(); 652 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT); 653 } 654 _SEH2_END; 655 656 // 657 // Parse the headers 658 // 659 if (NtHeaders) 660 { 661 // 662 // Use SEH in case we can't load the headers 663 // 664 _SEH2_TRY 665 { 666 // 667 // Get the Image Config Data too 668 // 669 ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, 670 TRUE, 671 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, 672 (PULONG)&ViewSize); 673 if (ImageConfigData) 674 { 675 // 676 // Probe it 677 // 678 ProbeForRead(ImageConfigData, 679 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY), 680 sizeof(ULONG)); 681 } 682 683 // 684 // Write subsystem data 685 // 686 Peb->ImageSubsystem = NtHeaders->OptionalHeader.Subsystem; 687 Peb->ImageSubsystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion; 688 Peb->ImageSubsystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion; 689 690 // 691 // Check for version data 692 // 693 if (NtHeaders->OptionalHeader.Win32VersionValue) 694 { 695 // 696 // Extract values and write them 697 // 698 Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF; 699 Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF; 700 Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF; 701 Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2; 702 703 /* Process CSD version override */ 704 if ((ImageConfigData) && (ImageConfigData->CSDVersion)) 705 { 706 /* Take the value from the image configuration directory */ 707 Peb->OSCSDVersion = ImageConfigData->CSDVersion; 708 } 709 } 710 711 /* Process optional process affinity mask override */ 712 if ((ImageConfigData) && (ImageConfigData->ProcessAffinityMask)) 713 { 714 /* Take the value from the image configuration directory */ 715 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask; 716 } 717 718 // 719 // Check if this is a UP image 720 if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) 721 { 722 // 723 // Force it to use CPU 0 724 // 725 /* FIXME: this should use the MmRotatingUniprocessorNumber */ 726 Peb->ImageProcessAffinityMask = 0; 727 } 728 else 729 { 730 // 731 // Whatever was configured 732 // 733 Peb->ImageProcessAffinityMask = ProcessAffinityMask; 734 } 735 } 736 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 737 { 738 // 739 // Fail 740 // 741 KeDetachProcess(); 742 _SEH2_YIELD(return STATUS_INVALID_IMAGE_PROTECT); 743 } 744 _SEH2_END; 745 } 746 747 // 748 // Detach from the Process 749 // 750 KeDetachProcess(); 751 *BasePeb = Peb; 752 return STATUS_SUCCESS; 753 } 754 755 NTSTATUS 756 NTAPI 757 MmCreateTeb(IN PEPROCESS Process, 758 IN PCLIENT_ID ClientId, 759 IN PINITIAL_TEB InitialTeb, 760 OUT PTEB *BaseTeb) 761 { 762 PTEB Teb; 763 NTSTATUS Status = STATUS_SUCCESS; 764 *BaseTeb = NULL; 765 766 // 767 // Attach to Target 768 // 769 KeAttachProcess(&Process->Pcb); 770 771 // 772 // Allocate the TEB 773 // 774 Status = MiCreatePebOrTeb(Process, sizeof(TEB), (PULONG_PTR)&Teb); 775 if (!NT_SUCCESS(Status)) 776 { 777 /* Cleanup and exit */ 778 KeDetachProcess(); 779 return Status; 780 } 781 782 // 783 // Use SEH in case we can't load the TEB 784 // 785 _SEH2_TRY 786 { 787 // 788 // Initialize the PEB 789 // 790 RtlZeroMemory(Teb, sizeof(TEB)); 791 792 // 793 // Set TIB Data 794 // 795 #ifdef _M_AMD64 796 Teb->NtTib.ExceptionList = NULL; 797 #else 798 Teb->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 799 #endif 800 Teb->NtTib.Self = (PNT_TIB)Teb; 801 802 // 803 // Identify this as an OS/2 V3.0 ("Cruiser") TIB 804 // 805 Teb->NtTib.Version = 30 << 8; 806 807 // 808 // Set TEB Data 809 // 810 Teb->ClientId = *ClientId; 811 Teb->RealClientId = *ClientId; 812 Teb->ProcessEnvironmentBlock = Process->Peb; 813 Teb->CurrentLocale = PsDefaultThreadLocaleId; 814 815 // 816 // Check if we have a grandparent TEB 817 // 818 if ((InitialTeb->PreviousStackBase == NULL) && 819 (InitialTeb->PreviousStackLimit == NULL)) 820 { 821 // 822 // Use initial TEB values 823 // 824 Teb->NtTib.StackBase = InitialTeb->StackBase; 825 Teb->NtTib.StackLimit = InitialTeb->StackLimit; 826 Teb->DeallocationStack = InitialTeb->AllocatedStackBase; 827 } 828 else 829 { 830 // 831 // Use grandparent TEB values 832 // 833 Teb->NtTib.StackBase = InitialTeb->PreviousStackBase; 834 Teb->NtTib.StackLimit = InitialTeb->PreviousStackLimit; 835 } 836 837 // 838 // Initialize the static unicode string 839 // 840 Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer); 841 Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer; 842 } 843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 844 { 845 // 846 // Get error code 847 // 848 Status = _SEH2_GetExceptionCode(); 849 } 850 _SEH2_END; 851 852 // 853 // Return 854 // 855 KeDetachProcess(); 856 *BaseTeb = Teb; 857 return Status; 858 } 859 860 #ifdef _M_AMD64 861 static 862 NTSTATUS 863 MiInsertSharedUserPageVad( 864 _In_ PEPROCESS Process) 865 { 866 PMMVAD_LONG Vad; 867 ULONG_PTR BaseAddress; 868 NTSTATUS Status; 869 870 if (Process->QuotaBlock != NULL) 871 { 872 Status = PsChargeProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG)); 873 if (!NT_SUCCESS(Status)) 874 { 875 DPRINT1("Ran out of quota.\n"); 876 return Status; 877 } 878 } 879 880 /* Allocate a VAD */ 881 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV'); 882 if (Vad == NULL) 883 { 884 DPRINT1("Failed to allocate VAD for shared user page\n"); 885 Status = STATUS_INSUFFICIENT_RESOURCES; 886 goto FailPath; 887 } 888 889 /* Setup the primary flags with the size, and make it private, RO */ 890 Vad->u.LongFlags = 0; 891 Vad->u.VadFlags.CommitCharge = 0; 892 Vad->u.VadFlags.NoChange = TRUE; 893 Vad->u.VadFlags.VadType = VadNone; 894 Vad->u.VadFlags.MemCommit = FALSE; 895 Vad->u.VadFlags.Protection = MM_READONLY; 896 Vad->u.VadFlags.PrivateMemory = TRUE; 897 Vad->u1.Parent = NULL; 898 899 /* Setup the secondary flags to make it a secured, readonly, long VAD */ 900 Vad->u2.LongFlags2 = 0; 901 Vad->u2.VadFlags2.OneSecured = TRUE; 902 Vad->u2.VadFlags2.LongVad = TRUE; 903 Vad->u2.VadFlags2.ReadOnly = FALSE; 904 905 Vad->ControlArea = NULL; // For Memory-Area hack 906 Vad->FirstPrototypePte = NULL; 907 908 /* Insert it into the process VAD table */ 909 BaseAddress = MM_SHARED_USER_DATA_VA; 910 Status = MiInsertVadEx((PMMVAD)Vad, 911 &BaseAddress, 912 PAGE_SIZE, 913 (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS, 914 PAGE_SIZE, 915 MEM_TOP_DOWN); 916 if (!NT_SUCCESS(Status)) 917 { 918 DPRINT1("Failed to insert shared user VAD\n"); 919 ExFreePoolWithTag(Vad, 'ldaV'); 920 goto FailPath; 921 } 922 923 /* Success */ 924 return STATUS_SUCCESS; 925 926 FailPath: 927 if (Process->QuotaBlock != NULL) 928 PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG)); 929 930 return Status; 931 } 932 #endif 933 934 NTSTATUS 935 NTAPI 936 MmInitializeProcessAddressSpace(IN PEPROCESS Process, 937 IN PEPROCESS ProcessClone OPTIONAL, 938 IN PVOID Section OPTIONAL, 939 IN OUT PULONG Flags, 940 IN POBJECT_NAME_INFORMATION *AuditName OPTIONAL) 941 { 942 NTSTATUS Status = STATUS_SUCCESS; 943 SIZE_T ViewSize = 0; 944 PVOID ImageBase = 0; 945 PMMPTE PointerPte; 946 KIRQL OldIrql; 947 PMMPDE PointerPde; 948 PMMPFN Pfn; 949 PFN_NUMBER PageFrameNumber; 950 UNICODE_STRING FileName; 951 PWCHAR Source; 952 PCHAR Destination; 953 USHORT Length = 0; 954 955 #if (_MI_PAGING_LEVELS >= 3) 956 PMMPPE PointerPpe; 957 #endif 958 #if (_MI_PAGING_LEVELS == 4) 959 PMMPXE PointerPxe; 960 #endif 961 962 /* We should have a PDE */ 963 ASSERT(Process->Pcb.DirectoryTableBase[0] != 0); 964 ASSERT(Process->PdeUpdateNeeded == FALSE); 965 966 /* Attach to the process */ 967 KeAttachProcess(&Process->Pcb); 968 969 /* The address space should now been in phase 1 or 0 */ 970 ASSERT(Process->AddressSpaceInitialized <= 1); 971 Process->AddressSpaceInitialized = 2; 972 973 /* Initialize the Addresss Space lock */ 974 KeInitializeGuardedMutex(&Process->AddressCreationLock); 975 Process->Vm.WorkingSetExpansionLinks.Flink = NULL; 976 977 /* Initialize AVL tree */ 978 ASSERT(Process->VadRoot.NumberGenericTableElements == 0); 979 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot; 980 981 /* Lock our working set */ 982 MiLockProcessWorkingSet(Process, PsGetCurrentThread()); 983 984 /* Lock PFN database */ 985 OldIrql = MiAcquirePfnLock(); 986 987 /* Setup the PFN for the PDE base of this process */ 988 #if (_MI_PAGING_LEVELS == 4) 989 PointerPte = MiAddressToPte(PXE_BASE); 990 #elif (_MI_PAGING_LEVELS == 3) 991 PointerPte = MiAddressToPte(PPE_BASE); 992 #else 993 PointerPte = MiAddressToPte(PDE_BASE); 994 #endif 995 PageFrameNumber = PFN_FROM_PTE(PointerPte); 996 ASSERT(Process->Pcb.DirectoryTableBase[0] == PageFrameNumber * PAGE_SIZE); 997 MiInitializePfn(PageFrameNumber, PointerPte, TRUE); 998 999 /* Do the same for hyperspace */ 1000 PointerPde = MiAddressToPde(HYPER_SPACE); 1001 PageFrameNumber = PFN_FROM_PTE(PointerPde); 1002 MiInitializePfn(PageFrameNumber, (PMMPTE)PointerPde, TRUE); 1003 #if (_MI_PAGING_LEVELS == 2) 1004 ASSERT(Process->Pcb.DirectoryTableBase[1] == PageFrameNumber * PAGE_SIZE); 1005 #endif 1006 1007 #if (_MI_PAGING_LEVELS >= 3) 1008 PointerPpe = MiAddressToPpe((PVOID)HYPER_SPACE); 1009 PageFrameNumber = PFN_FROM_PTE(PointerPpe); 1010 MiInitializePfn(PageFrameNumber, PointerPpe, TRUE); 1011 #if (_MI_PAGING_LEVELS == 3) 1012 ASSERT(Process->Pcb.DirectoryTableBase[1] == PageFrameNumber * PAGE_SIZE); 1013 #endif 1014 #endif 1015 #if (_MI_PAGING_LEVELS == 4) 1016 PointerPxe = MiAddressToPxe((PVOID)HYPER_SPACE); 1017 PageFrameNumber = PFN_FROM_PTE(PointerPxe); 1018 MiInitializePfn(PageFrameNumber, PointerPxe, TRUE); 1019 ASSERT(Process->Pcb.DirectoryTableBase[1] == PageFrameNumber * PAGE_SIZE); 1020 #endif 1021 1022 /* Do the same for the Working set list */ 1023 PointerPte = MiAddressToPte(MmWorkingSetList); 1024 PageFrameNumber = PFN_FROM_PTE(PointerPte); 1025 MiInitializePfn(PageFrameNumber, PointerPte, TRUE); 1026 1027 /* All our pages are now active & valid. Release the lock. */ 1028 MiReleasePfnLock(OldIrql); 1029 1030 /* This should be in hyper space, but not in the mapping range */ 1031 Process->Vm.VmWorkingSetList = MmWorkingSetList; 1032 ASSERT(((ULONG_PTR)MmWorkingSetList >= MI_MAPPING_RANGE_END) && ((ULONG_PTR)MmWorkingSetList <= HYPER_SPACE_END)); 1033 1034 /* Now initialize the working set list */ 1035 MiInitializeWorkingSetList(&Process->Vm); 1036 1037 /* The rule is that the owner process is always in the FLINK of the PDE's PFN entry */ 1038 Pfn = MiGetPfnEntry(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT); 1039 ASSERT(Pfn->u4.PteFrame == MiGetPfnEntryIndex(Pfn)); 1040 ASSERT(Pfn->u1.WsIndex == 0); 1041 Pfn->u1.Event = (PKEVENT)Process; 1042 1043 /* Sanity check */ 1044 ASSERT(Process->PhysicalVadRoot == NULL); 1045 1046 /* Release the process working set */ 1047 MiUnlockProcessWorkingSet(Process, PsGetCurrentThread()); 1048 1049 #ifdef _M_AMD64 1050 /* On x64 we need a VAD for the shared user page */ 1051 Status = MiInsertSharedUserPageVad(Process); 1052 if (!NT_SUCCESS(Status)) 1053 { 1054 DPRINT1("MiCreateSharedUserPageVad() failed: 0x%lx\n", Status); 1055 return Status; 1056 } 1057 #endif 1058 1059 /* Check if there's a Section Object */ 1060 if (Section) 1061 { 1062 /* Determine the image file name and save it to EPROCESS */ 1063 PFILE_OBJECT FileObject = MmGetFileObjectForSection(Section); 1064 FileName = FileObject->FileName; 1065 Source = (PWCHAR)((PCHAR)FileName.Buffer + FileName.Length); 1066 if (FileName.Buffer) 1067 { 1068 /* Loop the file name*/ 1069 while (Source > FileName.Buffer) 1070 { 1071 /* Make sure this isn't a backslash */ 1072 if (*--Source == OBJ_NAME_PATH_SEPARATOR) 1073 { 1074 /* If so, stop it here */ 1075 Source++; 1076 break; 1077 } 1078 else 1079 { 1080 /* Otherwise, keep going */ 1081 Length++; 1082 } 1083 } 1084 } 1085 1086 /* Copy the to the process and truncate it to 15 characters if necessary */ 1087 Destination = Process->ImageFileName; 1088 Length = min(Length, sizeof(Process->ImageFileName) - 1); 1089 while (Length--) *Destination++ = (UCHAR)*Source++; 1090 *Destination = ANSI_NULL; 1091 1092 /* Check if caller wants an audit name */ 1093 if (AuditName) 1094 { 1095 /* Setup the audit name */ 1096 Status = SeInitializeProcessAuditName(FileObject, FALSE, AuditName); 1097 if (!NT_SUCCESS(Status)) 1098 { 1099 /* Fail */ 1100 KeDetachProcess(); 1101 return Status; 1102 } 1103 } 1104 1105 /* Map the section */ 1106 Status = MmMapViewOfSection(Section, 1107 Process, 1108 (PVOID*)&ImageBase, 1109 0, 1110 0, 1111 NULL, 1112 &ViewSize, 1113 ViewUnmap, 1114 MEM_COMMIT, 1115 PAGE_READWRITE); 1116 1117 /* Save the pointer */ 1118 Process->SectionBaseAddress = ImageBase; 1119 } 1120 1121 /* Be nice and detach */ 1122 KeDetachProcess(); 1123 1124 /* Return status to caller */ 1125 return Status; 1126 } 1127 1128 CODE_SEG("INIT") 1129 NTSTATUS 1130 NTAPI 1131 MmInitializeHandBuiltProcess(IN PEPROCESS Process, 1132 IN PULONG_PTR DirectoryTableBase) 1133 { 1134 /* Share the directory base with the idle process */ 1135 DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]; 1136 DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1]; 1137 1138 /* Initialize the Addresss Space */ 1139 KeInitializeGuardedMutex(&Process->AddressCreationLock); 1140 KeInitializeSpinLock(&Process->HyperSpaceLock); 1141 Process->Vm.WorkingSetExpansionLinks.Flink = NULL; 1142 ASSERT(Process->VadRoot.NumberGenericTableElements == 0); 1143 Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot; 1144 1145 /* Use idle process Working set */ 1146 Process->Vm.VmWorkingSetList = PsGetCurrentProcess()->Vm.VmWorkingSetList; 1147 Process->WorkingSetPage = PsGetCurrentProcess()->WorkingSetPage; 1148 1149 /* Done */ 1150 Process->HasAddressSpace = TRUE;//?? 1151 return STATUS_SUCCESS; 1152 } 1153 1154 CODE_SEG("INIT") 1155 NTSTATUS 1156 NTAPI 1157 MmInitializeHandBuiltProcess2(IN PEPROCESS Process) 1158 { 1159 /* Lock the VAD, ARM3-owned ranges away */ 1160 return STATUS_SUCCESS; 1161 } 1162 1163 BOOLEAN 1164 NTAPI 1165 MmCreateProcessAddressSpace(IN ULONG MinWs, 1166 IN PEPROCESS Process, 1167 OUT PULONG_PTR DirectoryTableBase) 1168 { 1169 KIRQL OldIrql; 1170 PFN_NUMBER TableBaseIndex, HyperIndex, WsListIndex; 1171 ULONG Color; 1172 1173 /* Make sure we don't already have a page directory setup */ 1174 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0); 1175 ASSERT(Process->Pcb.DirectoryTableBase[1] == 0); 1176 ASSERT(Process->WorkingSetPage == 0); 1177 1178 /* Choose a process color */ 1179 Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed); 1180 1181 /* Setup the hyperspace lock */ 1182 KeInitializeSpinLock(&Process->HyperSpaceLock); 1183 1184 /* Lock PFN database */ 1185 OldIrql = MiAcquirePfnLock(); 1186 1187 /* 1188 * Get a page for the table base, one for hyper space & one for the working set list. 1189 * The PFNs for these pages will be initialized in MmInitializeProcessAddressSpace, 1190 * when we are already attached to the process. 1191 * The other pages (if any) are allocated in the arch-specific part. 1192 */ 1193 Color = MI_GET_NEXT_PROCESS_COLOR(Process); 1194 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY); 1195 TableBaseIndex = MiRemoveZeroPageSafe(Color); 1196 if (!TableBaseIndex) 1197 { 1198 /* No zero pages, grab a free one */ 1199 TableBaseIndex = MiRemoveAnyPage(Color); 1200 1201 /* Zero it outside the PFN lock */ 1202 MiReleasePfnLock(OldIrql); 1203 MiZeroPhysicalPage(TableBaseIndex); 1204 OldIrql = MiAcquirePfnLock(); 1205 } 1206 MI_SET_USAGE(MI_USAGE_PAGE_DIRECTORY); 1207 Color = MI_GET_NEXT_PROCESS_COLOR(Process); 1208 HyperIndex = MiRemoveZeroPageSafe(Color); 1209 if (!HyperIndex) 1210 { 1211 /* No zero pages, grab a free one */ 1212 HyperIndex = MiRemoveAnyPage(Color); 1213 1214 /* Zero it outside the PFN lock */ 1215 MiReleasePfnLock(OldIrql); 1216 MiZeroPhysicalPage(HyperIndex); 1217 OldIrql = MiAcquirePfnLock(); 1218 } 1219 MI_SET_USAGE(MI_USAGE_PAGE_TABLE); 1220 Color = MI_GET_NEXT_PROCESS_COLOR(Process); 1221 WsListIndex = MiRemoveZeroPageSafe(Color); 1222 if (!WsListIndex) 1223 { 1224 /* No zero pages, grab a free one */ 1225 WsListIndex = MiRemoveAnyPage(Color); 1226 1227 /* Zero it outside the PFN lock */ 1228 MiReleasePfnLock(OldIrql); 1229 MiZeroPhysicalPage(WsListIndex); 1230 } 1231 else 1232 { 1233 /* Release the PFN lock */ 1234 MiReleasePfnLock(OldIrql); 1235 } 1236 1237 /* Set the base directory pointers */ 1238 Process->WorkingSetPage = WsListIndex; 1239 DirectoryTableBase[0] = TableBaseIndex << PAGE_SHIFT; 1240 DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT; 1241 1242 /* Perform the arch-specific parts */ 1243 if (!MiArchCreateProcessAddressSpace(Process, DirectoryTableBase)) 1244 { 1245 OldIrql = MiAcquirePfnLock(); 1246 MiInsertPageInFreeList(WsListIndex); 1247 MiInsertPageInFreeList(HyperIndex); 1248 MiInsertPageInFreeList(TableBaseIndex); 1249 MiReleasePfnLock(OldIrql); 1250 Process->WorkingSetPage = 0; 1251 DirectoryTableBase[0] = 0; 1252 DirectoryTableBase[1] = 0; 1253 return FALSE; 1254 } 1255 1256 /* Switch to phase 1 initialization */ 1257 ASSERT(Process->AddressSpaceInitialized == 0); 1258 Process->AddressSpaceInitialized = 1; 1259 1260 /* Add the process to the session */ 1261 MiSessionAddProcess(Process); 1262 return TRUE; 1263 } 1264 1265 VOID 1266 NTAPI 1267 MmCleanProcessAddressSpace(IN PEPROCESS Process) 1268 { 1269 PMMVAD Vad; 1270 PMM_AVL_TABLE VadTree; 1271 PETHREAD Thread = PsGetCurrentThread(); 1272 1273 /* Remove from the session */ 1274 MiSessionRemoveProcess(); 1275 1276 /* Abort early, when the address space wasn't fully initialized */ 1277 if (Process->AddressSpaceInitialized < 2) 1278 { 1279 DPRINT1("Incomplete address space for Process %p. Might leak resources.\n", 1280 Process); 1281 return; 1282 } 1283 1284 /* Lock the process address space from changes */ 1285 MmLockAddressSpace(&Process->Vm); 1286 MiLockProcessWorkingSetUnsafe(Process, Thread); 1287 1288 /* VM is deleted now */ 1289 Process->VmDeleted = TRUE; 1290 MiUnlockProcessWorkingSetUnsafe(Process, Thread); 1291 1292 /* Enumerate the VADs */ 1293 VadTree = &Process->VadRoot; 1294 while (VadTree->NumberGenericTableElements) 1295 { 1296 /* Grab the current VAD */ 1297 Vad = (PMMVAD)VadTree->BalancedRoot.RightChild; 1298 1299 /* Check for old-style memory areas */ 1300 if (Vad->u.VadFlags.Spare == 1) 1301 { 1302 /* Let RosMm handle this */ 1303 MiRosCleanupMemoryArea(Process, Vad); 1304 continue; 1305 } 1306 1307 /* Lock the working set */ 1308 MiLockProcessWorkingSetUnsafe(Process, Thread); 1309 1310 /* Remove this VAD from the tree */ 1311 ASSERT(VadTree->NumberGenericTableElements >= 1); 1312 MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree); 1313 1314 /* Only regular VADs supported for now */ 1315 ASSERT(Vad->u.VadFlags.VadType == VadNone); 1316 1317 /* Check if this is a section VAD */ 1318 if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea)) 1319 { 1320 /* Remove the view */ 1321 MiRemoveMappedView(Process, Vad); 1322 } 1323 else 1324 { 1325 /* Delete the addresses */ 1326 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT, 1327 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1), 1328 Vad); 1329 1330 /* Release the working set */ 1331 MiUnlockProcessWorkingSetUnsafe(Process, Thread); 1332 } 1333 1334 /* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */ 1335 if (Vad->u.VadFlags.Spare == 1) 1336 { 1337 /* Set a flag so MmDeleteMemoryArea knows to free, but not to remove */ 1338 Vad->u.VadFlags.Spare = 2; 1339 continue; 1340 } 1341 1342 /* Free the VAD memory */ 1343 ExFreePool(Vad); 1344 1345 /* Return the quota the VAD used */ 1346 PsReturnProcessNonPagedPoolQuota(Process, sizeof(MMVAD_LONG)); 1347 } 1348 1349 /* Lock the working set */ 1350 MiLockProcessWorkingSetUnsafe(Process, Thread); 1351 ASSERT(Process->CloneRoot == NULL); 1352 ASSERT(Process->PhysicalVadRoot == NULL); 1353 1354 /* Delete the shared user data section */ 1355 MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL); 1356 1357 /* Release the working set */ 1358 MiUnlockProcessWorkingSetUnsafe(Process, Thread); 1359 1360 /* Release the address space */ 1361 MmUnlockAddressSpace(&Process->Vm); 1362 } 1363 1364 VOID 1365 NTAPI 1366 MmDeleteProcessAddressSpace(IN PEPROCESS Process) 1367 { 1368 PMMPFN Pfn1, Pfn2; 1369 KIRQL OldIrql; 1370 PFN_NUMBER PageFrameIndex; 1371 1372 #ifndef _M_AMD64 1373 OldIrql = MiAcquireExpansionLock(); 1374 RemoveEntryList(&Process->MmProcessLinks); 1375 MiReleaseExpansionLock(OldIrql); 1376 #endif 1377 1378 //ASSERT(Process->CommitCharge == 0); 1379 1380 /* Remove us from the list */ 1381 OldIrql = MiAcquireExpansionLock(); 1382 if (Process->Vm.WorkingSetExpansionLinks.Flink != NULL) 1383 RemoveEntryList(&Process->Vm.WorkingSetExpansionLinks); 1384 MiReleaseExpansionLock(OldIrql); 1385 1386 /* Acquire the PFN lock */ 1387 OldIrql = MiAcquirePfnLock(); 1388 1389 /* Check for fully initialized process */ 1390 if (Process->AddressSpaceInitialized == 2) 1391 { 1392 /* Map the working set page and its page table */ 1393 Pfn1 = MiGetPfnEntry(Process->WorkingSetPage); 1394 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame); 1395 1396 /* Nuke it */ 1397 MI_SET_PFN_DELETED(Pfn1); 1398 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame); 1399 MiDecrementShareCount(Pfn1, Process->WorkingSetPage); 1400 ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 1401 1402 /* Now map hyperspace and its page table */ 1403 PageFrameIndex = Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT; 1404 Pfn1 = MiGetPfnEntry(PageFrameIndex); 1405 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame); 1406 1407 /* Nuke it */ 1408 MI_SET_PFN_DELETED(Pfn1); 1409 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame); 1410 MiDecrementShareCount(Pfn1, PageFrameIndex); 1411 ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 1412 1413 /* Finally, nuke the PDE itself */ 1414 PageFrameIndex = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT; 1415 Pfn1 = MiGetPfnEntry(PageFrameIndex); 1416 MI_SET_PFN_DELETED(Pfn1); 1417 MiDecrementShareCount(Pfn1, PageFrameIndex); 1418 MiDecrementShareCount(Pfn1, PageFrameIndex); 1419 1420 /* Page table is now dead. Bye bye... */ 1421 ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 1422 } 1423 else 1424 { 1425 DPRINT1("Deleting partially initialized address space of Process %p. Might leak resources.\n", 1426 Process); 1427 } 1428 1429 /* Release the PFN lock */ 1430 MiReleasePfnLock(OldIrql); 1431 1432 /* Drop a reference on the session */ 1433 if (Process->Session) MiReleaseProcessReferenceToSessionDataPage(Process->Session); 1434 1435 /* Clear out the PDE pages */ 1436 Process->Pcb.DirectoryTableBase[0] = 0; 1437 Process->Pcb.DirectoryTableBase[1] = 0; 1438 } 1439 1440 1441 /* SYSTEM CALLS ***************************************************************/ 1442 1443 NTSTATUS 1444 NTAPI 1445 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle, 1446 IN OUT PULONG_PTR NumberOfPages, 1447 IN OUT PULONG_PTR UserPfnArray) 1448 { 1449 UNIMPLEMENTED; 1450 return STATUS_NOT_IMPLEMENTED; 1451 } 1452 1453 NTSTATUS 1454 NTAPI 1455 NtMapUserPhysicalPages(IN PVOID VirtualAddresses, 1456 IN ULONG_PTR NumberOfPages, 1457 IN OUT PULONG_PTR UserPfnArray) 1458 { 1459 UNIMPLEMENTED; 1460 return STATUS_NOT_IMPLEMENTED; 1461 } 1462 1463 NTSTATUS 1464 NTAPI 1465 NtMapUserPhysicalPagesScatter(IN PVOID *VirtualAddresses, 1466 IN ULONG_PTR NumberOfPages, 1467 IN OUT PULONG_PTR UserPfnArray) 1468 { 1469 UNIMPLEMENTED; 1470 return STATUS_NOT_IMPLEMENTED; 1471 } 1472 1473 NTSTATUS 1474 NTAPI 1475 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle, 1476 IN OUT PULONG_PTR NumberOfPages, 1477 IN OUT PULONG_PTR UserPfnArray) 1478 { 1479 UNIMPLEMENTED; 1480 return STATUS_NOT_IMPLEMENTED; 1481 } 1482 1483 /* EOF */ 1484