1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/procobj.c 5 * PURPOSE: Kernel Process Management and System Call Tables 6 * PROGRAMMERS: Alex Ionescu 7 * Gregor Anich 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 LIST_ENTRY KiProcessListHead; 19 LIST_ENTRY KiProcessInSwapListHead, KiProcessOutSwapListHead; 20 LIST_ENTRY KiStackInSwapListHead; 21 KEVENT KiSwapEvent; 22 23 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[SSDT_MAX_ENTRIES]; 24 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow[SSDT_MAX_ENTRIES]; 25 26 PVOID KeUserApcDispatcher; 27 PVOID KeUserCallbackDispatcher; 28 PVOID KeUserExceptionDispatcher; 29 PVOID KeRaiseUserExceptionDispatcher; 30 31 /* PRIVATE FUNCTIONS *********************************************************/ 32 33 VOID 34 NTAPI 35 KiAttachProcess(IN PKTHREAD Thread, 36 IN PKPROCESS Process, 37 IN PKLOCK_QUEUE_HANDLE ApcLock, 38 IN PRKAPC_STATE SavedApcState) 39 { 40 #if 0 41 PLIST_ENTRY ListHead, NextEntry; 42 PKTHREAD CurrentThread; 43 #endif 44 ASSERT(Process != Thread->ApcState.Process); 45 46 /* Increase Stack Count */ 47 ASSERT(Process->StackCount != MAXULONG_PTR); 48 Process->StackCount++; 49 50 /* Swap the APC Environment */ 51 KiMoveApcState(&Thread->ApcState, SavedApcState); 52 53 /* Reinitialize Apc State */ 54 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); 55 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); 56 Thread->ApcState.Process = Process; 57 Thread->ApcState.KernelApcInProgress = FALSE; 58 Thread->ApcState.KernelApcPending = FALSE; 59 Thread->ApcState.UserApcPending = FALSE; 60 61 /* Update Environment Pointers if needed*/ 62 if (SavedApcState == &Thread->SavedApcState) 63 { 64 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread-> 65 SavedApcState; 66 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState; 67 Thread->ApcStateIndex = AttachedApcEnvironment; 68 } 69 70 /* Check if the process is paged in */ 71 if (Process->State == ProcessInMemory) 72 { 73 /* Scan the ready list */ 74 #if 0 75 ListHead = &Process->ReadyListHead; 76 NextEntry = ListHead->Flink; 77 while (NextEntry != ListHead) 78 { 79 /* Get the thread */ 80 CurrentThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 81 82 /* Remove it */ 83 RemoveEntryList(NextEntry); 84 CurrentThread->ProcessReadyQueue = FALSE; 85 86 /* Mark it ready */ 87 KiReadyThread(CurrentThread); 88 89 /* Go to the next one */ 90 NextEntry = ListHead->Flink; 91 } 92 #endif 93 94 /* Release dispatcher lock */ 95 KiReleaseDispatcherLockFromSynchLevel(); 96 97 /* Release lock */ 98 KiReleaseApcLockFromSynchLevel(ApcLock); 99 100 /* Swap Processes */ 101 KiSwapProcess(Process, SavedApcState->Process); 102 103 /* Exit the dispatcher */ 104 KiExitDispatcher(ApcLock->OldIrql); 105 } 106 else 107 { 108 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n"); 109 ASSERT(FALSE); 110 } 111 } 112 113 VOID 114 NTAPI 115 KeInitializeProcess(IN OUT PKPROCESS Process, 116 IN KPRIORITY Priority, 117 IN KAFFINITY Affinity, 118 IN PULONG_PTR DirectoryTableBase, 119 IN BOOLEAN Enable) 120 { 121 #ifdef CONFIG_SMP 122 ULONG i = 0; 123 UCHAR IdealNode = 0; 124 PKNODE Node; 125 #endif 126 127 /* Initialize the Dispatcher Header */ 128 Process->Header.Type = ProcessObject; 129 Process->Header.Size = sizeof(KPROCESS) / sizeof(ULONG); 130 Process->Header.SignalState = 0; 131 InitializeListHead(&(Process->Header.WaitListHead)); 132 133 /* Initialize Scheduler Data, Alignment Faults and Set the PDE */ 134 Process->Affinity = Affinity; 135 Process->BasePriority = (CHAR)Priority; 136 Process->QuantumReset = 6; 137 Process->DirectoryTableBase[0] = DirectoryTableBase[0]; 138 Process->DirectoryTableBase[1] = DirectoryTableBase[1]; 139 Process->AutoAlignment = Enable; 140 #if defined(_M_IX86) 141 Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 142 #endif 143 144 /* Initialize the lists */ 145 InitializeListHead(&Process->ThreadListHead); 146 InitializeListHead(&Process->ProfileListHead); 147 InitializeListHead(&Process->ReadyListHead); 148 149 /* Initialize the current State */ 150 Process->State = ProcessInMemory; 151 152 /* Check how many Nodes there are on the system */ 153 #ifdef CONFIG_SMP 154 if (KeNumberNodes > 1) 155 { 156 /* Set the new seed */ 157 KeProcessNodeSeed = (KeProcessNodeSeed + 1) / KeNumberNodes; 158 IdealNode = KeProcessNodeSeed; 159 160 /* Loop every node */ 161 do 162 { 163 /* Check if the affinity matches */ 164 if (KeNodeBlock[IdealNode]->ProcessorMask != Affinity) break; 165 166 /* No match, try next Ideal Node and increase node loop index */ 167 IdealNode++; 168 i++; 169 170 /* Check if the Ideal Node is beyond the total number of nodes */ 171 if (IdealNode >= KeNumberNodes) 172 { 173 /* Normalize the Ideal Node */ 174 IdealNode -= KeNumberNodes; 175 } 176 } while (i < KeNumberNodes); 177 } 178 179 /* Set the ideal node and get the ideal node block */ 180 Process->IdealNode = IdealNode; 181 Node = KeNodeBlock[IdealNode]; 182 ASSERT(Node->ProcessorMask & Affinity); 183 184 /* Find the matching affinity set to calculate the thread seed */ 185 Affinity &= Node->ProcessorMask; 186 Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed, 187 (ULONG)Affinity); 188 Node->Seed = Process->ThreadSeed; 189 #endif 190 } 191 192 ULONG 193 NTAPI 194 KeSetProcess(IN PKPROCESS Process, 195 IN KPRIORITY Increment, 196 IN BOOLEAN InWait) 197 { 198 KIRQL OldIrql; 199 ULONG OldState; 200 ASSERT_PROCESS(Process); 201 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 202 203 /* Lock Dispatcher */ 204 OldIrql = KiAcquireDispatcherLock(); 205 206 /* Get Old State */ 207 OldState = Process->Header.SignalState; 208 209 /* Signal the Process */ 210 Process->Header.SignalState = TRUE; 211 212 /* Check if was unsignaled and has waiters */ 213 if (!(OldState) && 214 !(IsListEmpty(&Process->Header.WaitListHead))) 215 { 216 /* Unwait the threads */ 217 KxUnwaitThread(&Process->Header, Increment); 218 } 219 220 /* Release Dispatcher Database */ 221 KiReleaseDispatcherLock(OldIrql); 222 223 /* Return the previous State */ 224 return OldState; 225 } 226 227 VOID 228 NTAPI 229 KeSetQuantumProcess(IN PKPROCESS Process, 230 IN UCHAR Quantum) 231 { 232 KLOCK_QUEUE_HANDLE ProcessLock; 233 PLIST_ENTRY NextEntry, ListHead; 234 PKTHREAD Thread; 235 ASSERT_PROCESS(Process); 236 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 237 238 /* Lock the process */ 239 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 240 241 /* Set new quantum */ 242 Process->QuantumReset = Quantum; 243 244 /* Loop all child threads */ 245 ListHead = &Process->ThreadListHead; 246 NextEntry = ListHead->Flink; 247 while (ListHead != NextEntry) 248 { 249 /* Get the thread */ 250 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 251 252 /* Set quantum */ 253 Thread->QuantumReset = Quantum; 254 255 /* Go to the next one */ 256 NextEntry = NextEntry->Flink; 257 } 258 259 /* Release lock */ 260 KiReleaseProcessLock(&ProcessLock); 261 } 262 263 KAFFINITY 264 NTAPI 265 KeSetAffinityProcess(IN PKPROCESS Process, 266 IN KAFFINITY Affinity) 267 { 268 269 KLOCK_QUEUE_HANDLE ProcessLock; 270 PLIST_ENTRY NextEntry, ListHead; 271 KAFFINITY OldAffinity; 272 PKTHREAD Thread; 273 ASSERT_PROCESS(Process); 274 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 275 ASSERT((Affinity & KeActiveProcessors) != 0); 276 277 /* Lock the process */ 278 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 279 280 /* Acquire the dispatcher lock */ 281 KiAcquireDispatcherLockAtSynchLevel(); 282 283 /* Capture old affinity and update it */ 284 OldAffinity = Process->Affinity; 285 Process->Affinity = Affinity; 286 287 /* Loop all child threads */ 288 ListHead = &Process->ThreadListHead; 289 NextEntry = ListHead->Flink; 290 while (ListHead != NextEntry) 291 { 292 /* Get the thread */ 293 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 294 295 /* Set affinity on it */ 296 KiSetAffinityThread(Thread, Affinity); 297 NextEntry = NextEntry->Flink; 298 } 299 300 /* Release Dispatcher Database */ 301 KiReleaseDispatcherLockFromSynchLevel(); 302 303 /* Release the process lock */ 304 KiReleaseProcessLockFromSynchLevel(&ProcessLock); 305 KiExitDispatcher(ProcessLock.OldIrql); 306 307 /* Return previous affinity */ 308 return OldAffinity; 309 } 310 311 BOOLEAN 312 NTAPI 313 KeSetAutoAlignmentProcess(IN PKPROCESS Process, 314 IN BOOLEAN Enable) 315 { 316 /* Set or reset the bit depending on what the enable flag says */ 317 if (Enable) 318 { 319 return InterlockedBitTestAndSet(&Process->ProcessFlags, 320 KPSF_AUTO_ALIGNMENT_BIT); 321 } 322 else 323 { 324 return InterlockedBitTestAndReset(&Process->ProcessFlags, 325 KPSF_AUTO_ALIGNMENT_BIT); 326 } 327 } 328 329 BOOLEAN 330 NTAPI 331 KeSetDisableBoostProcess(IN PKPROCESS Process, 332 IN BOOLEAN Disable) 333 { 334 /* Set or reset the bit depending on what the disable flag says */ 335 if (Disable) 336 { 337 return InterlockedBitTestAndSet(&Process->ProcessFlags, 338 KPSF_DISABLE_BOOST_BIT); 339 } 340 else 341 { 342 return InterlockedBitTestAndReset(&Process->ProcessFlags, 343 KPSF_DISABLE_BOOST_BIT); 344 } 345 } 346 347 KPRIORITY 348 NTAPI 349 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process, 350 IN KPRIORITY Priority, 351 IN UCHAR Quantum OPTIONAL) 352 { 353 KLOCK_QUEUE_HANDLE ProcessLock; 354 KPRIORITY Delta; 355 PLIST_ENTRY NextEntry, ListHead; 356 KPRIORITY NewPriority, OldPriority; 357 PKTHREAD Thread; 358 ASSERT_PROCESS(Process); 359 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 360 361 /* Check if the process already has this priority */ 362 if (Process->BasePriority == Priority) return Process->BasePriority; 363 364 /* If the caller gave priority 0, normalize to 1 */ 365 if (!Priority) Priority = LOW_PRIORITY + 1; 366 367 /* Lock the process */ 368 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 369 370 /* Acquire the dispatcher lock */ 371 KiAcquireDispatcherLockAtSynchLevel(); 372 373 /* Check if we are modifying the quantum too */ 374 if (Quantum) Process->QuantumReset = Quantum; 375 376 /* Save the current base priority and update it */ 377 OldPriority = Process->BasePriority; 378 Process->BasePriority = (SCHAR)Priority; 379 380 /* Calculate the priority delta */ 381 Delta = Priority - OldPriority; 382 383 /* Set the list head and list entry */ 384 ListHead = &Process->ThreadListHead; 385 NextEntry = ListHead->Flink; 386 387 /* Check if this is a real-time priority */ 388 if (Priority >= LOW_REALTIME_PRIORITY) 389 { 390 /* Loop the thread list */ 391 while (NextEntry != ListHead) 392 { 393 /* Get the thread */ 394 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 395 396 /* Update the quantum if we had one */ 397 if (Quantum) Thread->QuantumReset = Quantum; 398 399 /* Acquire the thread lock */ 400 KiAcquireThreadLock(Thread); 401 402 /* Calculate the new priority */ 403 NewPriority = Thread->BasePriority + Delta; 404 if (NewPriority < LOW_REALTIME_PRIORITY) 405 { 406 /* We're in real-time range, don't let it go below */ 407 NewPriority = LOW_REALTIME_PRIORITY; 408 } 409 else if (NewPriority > HIGH_PRIORITY) 410 { 411 /* We're going beyond the maximum priority, normalize */ 412 NewPriority = HIGH_PRIORITY; 413 } 414 415 /* 416 * If priority saturation occured or the old priority was still in 417 * the real-time range, don't do anything. 418 */ 419 if (!(Thread->Saturation) || (OldPriority < LOW_REALTIME_PRIORITY)) 420 { 421 /* Check if we had priority saturation */ 422 if (Thread->Saturation > 0) 423 { 424 /* Boost priority to maximum */ 425 NewPriority = HIGH_PRIORITY; 426 } 427 else if (Thread->Saturation < 0) 428 { 429 /* If we had negative saturation, set minimum priority */ 430 NewPriority = LOW_REALTIME_PRIORITY; 431 } 432 433 /* Update priority and quantum */ 434 Thread->BasePriority = (SCHAR)NewPriority; 435 Thread->Quantum = Thread->QuantumReset; 436 437 /* Disable decrements and update priority */ 438 Thread->PriorityDecrement = 0; 439 KiSetPriorityThread(Thread, NewPriority); 440 } 441 442 /* Release the thread lock */ 443 KiReleaseThreadLock(Thread); 444 445 /* Go to the next thread */ 446 NextEntry = NextEntry->Flink; 447 } 448 } 449 else 450 { 451 /* Loop the thread list */ 452 while (NextEntry != ListHead) 453 { 454 /* Get the thread */ 455 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 456 457 /* Update the quantum if we had one */ 458 if (Quantum) Thread->QuantumReset = Quantum; 459 460 /* Lock the thread */ 461 KiAcquireThreadLock(Thread); 462 463 /* Calculate the new priority */ 464 NewPriority = Thread->BasePriority + Delta; 465 if (NewPriority >= LOW_REALTIME_PRIORITY) 466 { 467 /* We're not real-time range, don't let it enter RT range */ 468 NewPriority = LOW_REALTIME_PRIORITY - 1; 469 } 470 else if (NewPriority <= LOW_PRIORITY) 471 { 472 /* We're going below the minimum priority, normalize */ 473 NewPriority = 1; 474 } 475 476 /* 477 * If priority saturation occured or the old priority was still in 478 * the real-time range, don't do anything. 479 */ 480 if (!(Thread->Saturation) || 481 (OldPriority >= LOW_REALTIME_PRIORITY)) 482 { 483 /* Check if we had priority saturation */ 484 if (Thread->Saturation > 0) 485 { 486 /* Boost priority to maximum */ 487 NewPriority = LOW_REALTIME_PRIORITY - 1; 488 } 489 else if (Thread->Saturation < 0) 490 { 491 /* If we had negative saturation, set minimum priority */ 492 NewPriority = 1; 493 } 494 495 /* Update priority and quantum */ 496 Thread->BasePriority = (SCHAR)NewPriority; 497 Thread->Quantum = Thread->QuantumReset; 498 499 /* Disable decrements and update priority */ 500 Thread->PriorityDecrement = 0; 501 KiSetPriorityThread(Thread, NewPriority); 502 } 503 504 /* Release the thread lock */ 505 KiReleaseThreadLock(Thread); 506 507 /* Go to the next thread */ 508 NextEntry = NextEntry->Flink; 509 } 510 } 511 512 /* Release Dispatcher Database */ 513 KiReleaseDispatcherLockFromSynchLevel(); 514 515 /* Release the process lock */ 516 KiReleaseProcessLockFromSynchLevel(&ProcessLock); 517 KiExitDispatcher(ProcessLock.OldIrql); 518 519 /* Return previous priority */ 520 return OldPriority; 521 } 522 523 VOID 524 NTAPI 525 KeQueryValuesProcess(IN PKPROCESS Process, 526 PPROCESS_VALUES Values) 527 { 528 PEPROCESS EProcess; 529 PLIST_ENTRY NextEntry; 530 ULONG TotalKernel, TotalUser; 531 KLOCK_QUEUE_HANDLE ProcessLock; 532 533 ASSERT_PROCESS(Process); 534 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 535 536 /* Lock the process */ 537 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 538 539 /* Initialize user and kernel times */ 540 TotalKernel = Process->KernelTime; 541 TotalUser = Process->UserTime; 542 543 /* Copy the IO_COUNTERS from the process */ 544 EProcess = (PEPROCESS)Process; 545 Values->IoInfo.ReadOperationCount = EProcess->ReadOperationCount.QuadPart; 546 Values->IoInfo.WriteOperationCount = EProcess->WriteOperationCount.QuadPart; 547 Values->IoInfo.OtherOperationCount = EProcess->OtherOperationCount.QuadPart; 548 Values->IoInfo.ReadTransferCount = EProcess->ReadTransferCount.QuadPart; 549 Values->IoInfo.WriteTransferCount = EProcess->WriteTransferCount.QuadPart; 550 Values->IoInfo.OtherTransferCount = EProcess->OtherTransferCount.QuadPart; 551 552 /* Loop all child threads and sum up their times */ 553 for (NextEntry = Process->ThreadListHead.Flink; 554 NextEntry != &Process->ThreadListHead; 555 NextEntry = NextEntry->Flink) 556 { 557 PKTHREAD Thread; 558 559 /* Get the thread */ 560 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 561 562 /* Sum up times */ 563 TotalKernel += Thread->KernelTime; 564 TotalUser += Thread->UserTime; 565 } 566 567 /* Release the process lock */ 568 KiReleaseProcessLock(&ProcessLock); 569 570 /* Compute total times */ 571 Values->TotalKernelTime.QuadPart = TotalKernel * (LONGLONG)KeMaximumIncrement; 572 Values->TotalUserTime.QuadPart = TotalUser * (LONGLONG)KeMaximumIncrement; 573 } 574 575 /* PUBLIC FUNCTIONS **********************************************************/ 576 577 /* 578 * @implemented 579 */ 580 VOID 581 NTAPI 582 KeAttachProcess(IN PKPROCESS Process) 583 { 584 KLOCK_QUEUE_HANDLE ApcLock; 585 PKTHREAD Thread = KeGetCurrentThread(); 586 ASSERT_PROCESS(Process); 587 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 588 589 /* Check if we're already in that process */ 590 if (Thread->ApcState.Process == Process) return; 591 592 /* Check if a DPC is executing or if we're already attached */ 593 if ((Thread->ApcStateIndex != OriginalApcEnvironment) || 594 (KeIsExecutingDpc())) 595 { 596 /* Invalid attempt */ 597 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 598 (ULONG_PTR)Process, 599 (ULONG_PTR)Thread->ApcState.Process, 600 Thread->ApcStateIndex, 601 KeIsExecutingDpc()); 602 } 603 else 604 { 605 /* Acquire APC Lock */ 606 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 607 608 /* Acquire the dispatcher lock */ 609 KiAcquireDispatcherLockAtSynchLevel(); 610 611 /* Legit attach attempt: do it! */ 612 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 613 } 614 } 615 616 /* 617 * @implemented 618 */ 619 VOID 620 NTAPI 621 KeDetachProcess(VOID) 622 { 623 PKTHREAD Thread = KeGetCurrentThread(); 624 KLOCK_QUEUE_HANDLE ApcLock; 625 PKPROCESS Process; 626 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 627 628 /* Check if it's attached */ 629 if (Thread->ApcStateIndex == OriginalApcEnvironment) return; 630 631 /* Acquire APC Lock */ 632 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 633 634 /* Check for invalid attach attempts */ 635 if ((Thread->ApcState.KernelApcInProgress) || 636 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 637 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 638 { 639 /* Crash the system */ 640 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 641 } 642 643 /* Get the process */ 644 Process = Thread->ApcState.Process; 645 646 /* Acquire dispatcher lock */ 647 KiAcquireDispatcherLockAtSynchLevel(); 648 649 /* Decrease the stack count */ 650 ASSERT(Process->StackCount != 0); 651 ASSERT(Process->State == ProcessInMemory); 652 Process->StackCount--; 653 654 /* Check if we can swap the process out */ 655 if (!Process->StackCount) 656 { 657 /* FIXME: Swap the process out */ 658 } 659 660 /* Release dispatcher lock */ 661 KiReleaseDispatcherLockFromSynchLevel(); 662 663 /* Restore the APC State */ 664 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 665 Thread->SavedApcState.Process = NULL; 666 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 667 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 668 Thread->ApcStateIndex = OriginalApcEnvironment; 669 670 /* Release lock */ 671 KiReleaseApcLockFromSynchLevel(&ApcLock); 672 673 /* Swap Processes */ 674 KiSwapProcess(Thread->ApcState.Process, Process); 675 676 /* Exit the dispatcher */ 677 KiExitDispatcher(ApcLock.OldIrql); 678 679 /* Check if we have pending APCs */ 680 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 681 { 682 /* What do you know, we do! Request them to be delivered */ 683 Thread->ApcState.KernelApcPending = TRUE; 684 HalRequestSoftwareInterrupt(APC_LEVEL); 685 } 686 } 687 688 /* 689 * @implemented 690 */ 691 BOOLEAN 692 NTAPI 693 KeIsAttachedProcess(VOID) 694 { 695 /* Return the APC State */ 696 return KeGetCurrentThread()->ApcStateIndex; 697 } 698 699 /* 700 * @implemented 701 */ 702 VOID 703 NTAPI 704 KeStackAttachProcess(IN PKPROCESS Process, 705 OUT PRKAPC_STATE ApcState) 706 { 707 KLOCK_QUEUE_HANDLE ApcLock; 708 PKTHREAD Thread = KeGetCurrentThread(); 709 ASSERT_PROCESS(Process); 710 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 711 712 /* Crash system if DPC is being executed! */ 713 if (KeIsExecutingDpc()) 714 { 715 /* Executing a DPC, crash! */ 716 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 717 (ULONG_PTR)Process, 718 (ULONG_PTR)Thread->ApcState.Process, 719 Thread->ApcStateIndex, 720 KeIsExecutingDpc()); 721 } 722 723 /* Check if we are already in the target process */ 724 if (Thread->ApcState.Process == Process) 725 { 726 /* Set magic value so we don't crash later when detaching */ 727 ApcState->Process = (PKPROCESS)1; 728 return; 729 } 730 731 /* Acquire APC Lock */ 732 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 733 734 /* Acquire dispatcher lock */ 735 KiAcquireDispatcherLockAtSynchLevel(); 736 737 /* Check if the Current Thread is already attached */ 738 if (Thread->ApcStateIndex != OriginalApcEnvironment) 739 { 740 /* We're already attached, so save the APC State into what we got */ 741 KiAttachProcess(Thread, Process, &ApcLock, ApcState); 742 } 743 else 744 { 745 /* We're not attached, so save the APC State into SavedApcState */ 746 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 747 ApcState->Process = NULL; 748 } 749 } 750 751 /* 752 * @implemented 753 */ 754 VOID 755 NTAPI 756 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) 757 { 758 KLOCK_QUEUE_HANDLE ApcLock; 759 PKTHREAD Thread = KeGetCurrentThread(); 760 PKPROCESS Process; 761 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 762 763 /* Check for magic value meaning we were already in the same process */ 764 if (ApcState->Process == (PKPROCESS)1) return; 765 766 /* Loop to make sure no APCs are pending */ 767 for (;;) 768 { 769 /* Acquire APC Lock */ 770 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 771 772 /* Check if a kernel APC is pending */ 773 if (Thread->ApcState.KernelApcPending) 774 { 775 /* Check if kernel APC should be delivered */ 776 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL)) 777 { 778 /* Release the APC lock so that the APC can be delivered */ 779 KiReleaseApcLock(&ApcLock); 780 continue; 781 } 782 } 783 784 /* Otherwise, break out */ 785 break; 786 } 787 788 /* 789 * Check if the process isn't attacked, or has a Kernel APC in progress 790 * or has pending APC of any kind. 791 */ 792 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || 793 (Thread->ApcState.KernelApcInProgress) || 794 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 795 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 796 { 797 /* Bugcheck the system */ 798 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 799 } 800 801 /* Get the process */ 802 Process = Thread->ApcState.Process; 803 804 /* Acquire dispatcher lock */ 805 KiAcquireDispatcherLockAtSynchLevel(); 806 807 /* Decrease the stack count */ 808 ASSERT(Process->StackCount != 0); 809 ASSERT(Process->State == ProcessInMemory); 810 Process->StackCount--; 811 812 /* Check if we can swap the process out */ 813 if (!Process->StackCount) 814 { 815 /* FIXME: Swap the process out */ 816 } 817 818 /* Release dispatcher lock */ 819 KiReleaseDispatcherLockFromSynchLevel(); 820 821 /* Check if there's an APC state to restore */ 822 if (ApcState->Process) 823 { 824 /* Restore the APC State */ 825 KiMoveApcState(ApcState, &Thread->ApcState); 826 } 827 else 828 { 829 /* The ApcState parameter is useless, so use the saved data and reset it */ 830 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 831 Thread->SavedApcState.Process = NULL; 832 Thread->ApcStateIndex = OriginalApcEnvironment; 833 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 834 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 835 } 836 837 /* Release lock */ 838 KiReleaseApcLockFromSynchLevel(&ApcLock); 839 840 /* Swap Processes */ 841 KiSwapProcess(Thread->ApcState.Process, Process); 842 843 /* Exit the dispatcher */ 844 KiExitDispatcher(ApcLock.OldIrql); 845 846 /* Check if we have pending APCs */ 847 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 848 { 849 /* What do you know, we do! Request them to be delivered */ 850 Thread->ApcState.KernelApcPending = TRUE; 851 HalRequestSoftwareInterrupt(APC_LEVEL); 852 } 853 } 854 855 /* 856 * @implemented 857 */ 858 ULONG 859 NTAPI 860 KeQueryRuntimeProcess(IN PKPROCESS Process, 861 OUT PULONG UserTime) 862 { 863 ULONG TotalUser, TotalKernel; 864 KLOCK_QUEUE_HANDLE ProcessLock; 865 PLIST_ENTRY NextEntry, ListHead; 866 PKTHREAD Thread; 867 868 ASSERT_PROCESS(Process); 869 870 /* Initialize user and kernel times */ 871 TotalUser = Process->UserTime; 872 TotalKernel = Process->KernelTime; 873 874 /* Lock the process */ 875 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 876 877 /* Loop all child threads and sum up their times */ 878 ListHead = &Process->ThreadListHead; 879 NextEntry = ListHead->Flink; 880 while (ListHead != NextEntry) 881 { 882 /* Get the thread */ 883 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 884 885 /* Sum up times */ 886 TotalKernel += Thread->KernelTime; 887 TotalUser += Thread->UserTime; 888 889 /* Go to the next one */ 890 NextEntry = NextEntry->Flink; 891 } 892 893 /* Release lock */ 894 KiReleaseProcessLock(&ProcessLock); 895 896 /* Return the user time */ 897 *UserTime = TotalUser; 898 899 /* Return the kernel time */ 900 return TotalKernel; 901 } 902 903 /* 904 * @implemented 905 */ 906 BOOLEAN 907 NTAPI 908 KeAddSystemServiceTable(IN PULONG_PTR Base, 909 IN PULONG Count OPTIONAL, 910 IN ULONG Limit, 911 IN PUCHAR Number, 912 IN ULONG Index) 913 { 914 PAGED_CODE(); 915 916 /* Check if descriptor table entry is free */ 917 if ((Index > SSDT_MAX_ENTRIES - 1) || 918 (KeServiceDescriptorTable[Index].Base) || 919 (KeServiceDescriptorTableShadow[Index].Base)) 920 { 921 /* It's not, fail */ 922 return FALSE; 923 } 924 925 /* Initialize the shadow service descriptor table */ 926 KeServiceDescriptorTableShadow[Index].Base = Base; 927 KeServiceDescriptorTableShadow[Index].Limit = Limit; 928 KeServiceDescriptorTableShadow[Index].Number = Number; 929 KeServiceDescriptorTableShadow[Index].Count = Count; 930 return TRUE; 931 } 932 933 /* 934 * @implemented 935 */ 936 BOOLEAN 937 NTAPI 938 KeRemoveSystemServiceTable(IN ULONG Index) 939 { 940 PAGED_CODE(); 941 942 /* Make sure the Index is valid */ 943 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE; 944 945 /* Is there a Normal Descriptor Table? */ 946 if (!KeServiceDescriptorTable[Index].Base) 947 { 948 /* Not with the index, is there a shadow at least? */ 949 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE; 950 } 951 952 /* Now clear from the Shadow Table. */ 953 KeServiceDescriptorTableShadow[Index].Base = NULL; 954 KeServiceDescriptorTableShadow[Index].Number = NULL; 955 KeServiceDescriptorTableShadow[Index].Limit = 0; 956 KeServiceDescriptorTableShadow[Index].Count = NULL; 957 958 /* Check if we should clean from the Master one too */ 959 if (Index == 1) 960 { 961 KeServiceDescriptorTable[Index].Base = NULL; 962 KeServiceDescriptorTable[Index].Number = NULL; 963 KeServiceDescriptorTable[Index].Limit = 0; 964 KeServiceDescriptorTable[Index].Count = NULL; 965 } 966 967 /* Return success */ 968 return TRUE; 969 } 970 /* EOF */ 971