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