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 KiReleaseDispatcherLockFromDpcLevel(); 96 97 /* Release lock */ 98 KiReleaseApcLockFromDpcLevel(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 KiAcquireProcessLock(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 KiAcquireProcessLock(Process, &ProcessLock); 279 280 /* Acquire the dispatcher lock */ 281 KiAcquireDispatcherLockAtDpcLevel(); 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 KiReleaseDispatcherLockFromDpcLevel(); 302 303 /* Release the process lock */ 304 KiReleaseProcessLockFromDpcLevel(&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 KiAcquireProcessLock(Process, &ProcessLock); 369 370 /* Check if we are modifying the quantum too */ 371 if (Quantum) Process->QuantumReset = Quantum; 372 373 /* Save the current base priority and update it */ 374 OldPriority = Process->BasePriority; 375 Process->BasePriority = (SCHAR)Priority; 376 377 /* Calculate the priority delta */ 378 Delta = Priority - OldPriority; 379 380 /* Set the list head and list entry */ 381 ListHead = &Process->ThreadListHead; 382 NextEntry = ListHead->Flink; 383 384 /* Check if this is a real-time priority */ 385 if (Priority >= LOW_REALTIME_PRIORITY) 386 { 387 /* Loop the thread list */ 388 while (NextEntry != ListHead) 389 { 390 /* Get the thread */ 391 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 392 393 /* Update the quantum if we had one */ 394 if (Quantum) Thread->QuantumReset = Quantum; 395 396 /* Acquire the thread lock */ 397 KiAcquireThreadLock(Thread); 398 399 /* Calculate the new priority */ 400 NewPriority = Thread->BasePriority + Delta; 401 if (NewPriority < LOW_REALTIME_PRIORITY) 402 { 403 /* We're in real-time range, don't let it go below */ 404 NewPriority = LOW_REALTIME_PRIORITY; 405 } 406 else if (NewPriority > HIGH_PRIORITY) 407 { 408 /* We're going beyond the maximum priority, normalize */ 409 NewPriority = HIGH_PRIORITY; 410 } 411 412 /* 413 * If priority saturation occured or the old priority was still in 414 * the real-time range, don't do anything. 415 */ 416 if (!(Thread->Saturation) || (OldPriority < LOW_REALTIME_PRIORITY)) 417 { 418 /* Check if we had priority saturation */ 419 if (Thread->Saturation > 0) 420 { 421 /* Boost priority to maximum */ 422 NewPriority = HIGH_PRIORITY; 423 } 424 else if (Thread->Saturation < 0) 425 { 426 /* If we had negative saturation, set minimum priority */ 427 NewPriority = LOW_REALTIME_PRIORITY; 428 } 429 430 /* Update priority and quantum */ 431 Thread->BasePriority = (SCHAR)NewPriority; 432 Thread->Quantum = Thread->QuantumReset; 433 434 /* Disable decrements and update priority */ 435 Thread->PriorityDecrement = 0; 436 KiSetPriorityThread(Thread, NewPriority); 437 } 438 439 /* Release the thread lock */ 440 KiReleaseThreadLock(Thread); 441 442 /* Go to the next thread */ 443 NextEntry = NextEntry->Flink; 444 } 445 } 446 else 447 { 448 /* Loop the thread list */ 449 while (NextEntry != ListHead) 450 { 451 /* Get the thread */ 452 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 453 454 /* Update the quantum if we had one */ 455 if (Quantum) Thread->QuantumReset = Quantum; 456 457 /* Lock the thread */ 458 KiAcquireThreadLock(Thread); 459 460 /* Calculate the new priority */ 461 NewPriority = Thread->BasePriority + Delta; 462 if (NewPriority >= LOW_REALTIME_PRIORITY) 463 { 464 /* We're not real-time range, don't let it enter RT range */ 465 NewPriority = LOW_REALTIME_PRIORITY - 1; 466 } 467 else if (NewPriority <= LOW_PRIORITY) 468 { 469 /* We're going below the minimum priority, normalize */ 470 NewPriority = 1; 471 } 472 473 /* 474 * If priority saturation occured or the old priority was still in 475 * the real-time range, don't do anything. 476 */ 477 if (!(Thread->Saturation) || 478 (OldPriority >= LOW_REALTIME_PRIORITY)) 479 { 480 /* Check if we had priority saturation */ 481 if (Thread->Saturation > 0) 482 { 483 /* Boost priority to maximum */ 484 NewPriority = LOW_REALTIME_PRIORITY - 1; 485 } 486 else if (Thread->Saturation < 0) 487 { 488 /* If we had negative saturation, set minimum priority */ 489 NewPriority = 1; 490 } 491 492 /* Update priority and quantum */ 493 Thread->BasePriority = (SCHAR)NewPriority; 494 Thread->Quantum = Thread->QuantumReset; 495 496 /* Disable decrements and update priority */ 497 Thread->PriorityDecrement = 0; 498 KiSetPriorityThread(Thread, NewPriority); 499 } 500 501 /* Release the thread lock */ 502 KiReleaseThreadLock(Thread); 503 504 /* Go to the next thread */ 505 NextEntry = NextEntry->Flink; 506 } 507 } 508 509 /* Release Dispatcher Database */ 510 KiReleaseDispatcherLockFromDpcLevel(); 511 512 /* Release the process lock */ 513 KiReleaseProcessLockFromDpcLevel(&ProcessLock); 514 KiExitDispatcher(ProcessLock.OldIrql); 515 516 /* Return previous priority */ 517 return OldPriority; 518 } 519 520 /* PUBLIC FUNCTIONS **********************************************************/ 521 522 /* 523 * @implemented 524 */ 525 VOID 526 NTAPI 527 KeAttachProcess(IN PKPROCESS Process) 528 { 529 KLOCK_QUEUE_HANDLE ApcLock; 530 PKTHREAD Thread = KeGetCurrentThread(); 531 ASSERT_PROCESS(Process); 532 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 533 534 /* Check if we're already in that process */ 535 if (Thread->ApcState.Process == Process) return; 536 537 /* Check if a DPC is executing or if we're already attached */ 538 if ((Thread->ApcStateIndex != OriginalApcEnvironment) || 539 (KeIsExecutingDpc())) 540 { 541 /* Invalid attempt */ 542 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 543 (ULONG_PTR)Process, 544 (ULONG_PTR)Thread->ApcState.Process, 545 Thread->ApcStateIndex, 546 KeIsExecutingDpc()); 547 } 548 else 549 { 550 /* Acquire APC Lock */ 551 KiAcquireApcLock(Thread, &ApcLock); 552 553 /* Acquire the dispatcher lock */ 554 KiAcquireDispatcherLockAtDpcLevel(); 555 556 /* Legit attach attempt: do it! */ 557 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 558 } 559 } 560 561 /* 562 * @implemented 563 */ 564 VOID 565 NTAPI 566 KeDetachProcess(VOID) 567 { 568 PKTHREAD Thread = KeGetCurrentThread(); 569 KLOCK_QUEUE_HANDLE ApcLock; 570 PKPROCESS Process; 571 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 572 573 /* Check if it's attached */ 574 if (Thread->ApcStateIndex == OriginalApcEnvironment) return; 575 576 /* Acquire APC Lock */ 577 KiAcquireApcLock(Thread, &ApcLock); 578 579 /* Check for invalid attach attempts */ 580 if ((Thread->ApcState.KernelApcInProgress) || 581 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 582 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 583 { 584 /* Crash the system */ 585 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 586 } 587 588 /* Get the process */ 589 Process = Thread->ApcState.Process; 590 591 /* Acquire dispatcher lock */ 592 KiAcquireDispatcherLockAtDpcLevel(); 593 594 /* Decrease the stack count */ 595 ASSERT(Process->StackCount != 0); 596 ASSERT(Process->State == ProcessInMemory); 597 Process->StackCount--; 598 599 /* Check if we can swap the process out */ 600 if (!Process->StackCount) 601 { 602 /* FIXME: Swap the process out */ 603 } 604 605 /* Release dispatcher lock */ 606 KiReleaseDispatcherLockFromDpcLevel(); 607 608 /* Restore the APC State */ 609 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 610 Thread->SavedApcState.Process = NULL; 611 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 612 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 613 Thread->ApcStateIndex = OriginalApcEnvironment; 614 615 /* Release lock */ 616 KiReleaseApcLockFromDpcLevel(&ApcLock); 617 618 /* Swap Processes */ 619 KiSwapProcess(Thread->ApcState.Process, Process); 620 621 /* Exit the dispatcher */ 622 KiExitDispatcher(ApcLock.OldIrql); 623 624 /* Check if we have pending APCs */ 625 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 626 { 627 /* What do you know, we do! Request them to be delivered */ 628 Thread->ApcState.KernelApcPending = TRUE; 629 HalRequestSoftwareInterrupt(APC_LEVEL); 630 } 631 } 632 633 /* 634 * @implemented 635 */ 636 BOOLEAN 637 NTAPI 638 KeIsAttachedProcess(VOID) 639 { 640 /* Return the APC State */ 641 return KeGetCurrentThread()->ApcStateIndex; 642 } 643 644 /* 645 * @implemented 646 */ 647 VOID 648 NTAPI 649 KeStackAttachProcess(IN PKPROCESS Process, 650 OUT PRKAPC_STATE ApcState) 651 { 652 KLOCK_QUEUE_HANDLE ApcLock; 653 PKTHREAD Thread = KeGetCurrentThread(); 654 ASSERT_PROCESS(Process); 655 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 656 657 /* Crash system if DPC is being executed! */ 658 if (KeIsExecutingDpc()) 659 { 660 /* Executing a DPC, crash! */ 661 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 662 (ULONG_PTR)Process, 663 (ULONG_PTR)Thread->ApcState.Process, 664 Thread->ApcStateIndex, 665 KeIsExecutingDpc()); 666 } 667 668 /* Check if we are already in the target process */ 669 if (Thread->ApcState.Process == Process) 670 { 671 /* Set magic value so we don't crash later when detaching */ 672 ApcState->Process = (PKPROCESS)1; 673 return; 674 } 675 676 /* Acquire APC Lock */ 677 KiAcquireApcLock(Thread, &ApcLock); 678 679 /* Acquire dispatcher lock */ 680 KiAcquireDispatcherLockAtDpcLevel(); 681 682 /* Check if the Current Thread is already attached */ 683 if (Thread->ApcStateIndex != OriginalApcEnvironment) 684 { 685 /* We're already attached, so save the APC State into what we got */ 686 KiAttachProcess(Thread, Process, &ApcLock, ApcState); 687 } 688 else 689 { 690 /* We're not attached, so save the APC State into SavedApcState */ 691 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 692 ApcState->Process = NULL; 693 } 694 } 695 696 /* 697 * @implemented 698 */ 699 VOID 700 NTAPI 701 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) 702 { 703 KLOCK_QUEUE_HANDLE ApcLock; 704 PKTHREAD Thread = KeGetCurrentThread(); 705 PKPROCESS Process; 706 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 707 708 /* Check for magic value meaning we were already in the same process */ 709 if (ApcState->Process == (PKPROCESS)1) return; 710 711 /* Loop to make sure no APCs are pending */ 712 for (;;) 713 { 714 /* Acquire APC Lock */ 715 KiAcquireApcLock(Thread, &ApcLock); 716 717 /* Check if a kernel APC is pending */ 718 if (Thread->ApcState.KernelApcPending) 719 { 720 /* Check if kernel APC should be delivered */ 721 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL)) 722 { 723 /* Release the APC lock so that the APC can be delivered */ 724 KiReleaseApcLock(&ApcLock); 725 continue; 726 } 727 } 728 729 /* Otherwise, break out */ 730 break; 731 } 732 733 /* 734 * Check if the process isn't attacked, or has a Kernel APC in progress 735 * or has pending APC of any kind. 736 */ 737 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || 738 (Thread->ApcState.KernelApcInProgress) || 739 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 740 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 741 { 742 /* Bugcheck the system */ 743 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 744 } 745 746 /* Get the process */ 747 Process = Thread->ApcState.Process; 748 749 /* Acquire dispatcher lock */ 750 KiAcquireDispatcherLockAtDpcLevel(); 751 752 /* Decrease the stack count */ 753 ASSERT(Process->StackCount != 0); 754 ASSERT(Process->State == ProcessInMemory); 755 Process->StackCount--; 756 757 /* Check if we can swap the process out */ 758 if (!Process->StackCount) 759 { 760 /* FIXME: Swap the process out */ 761 } 762 763 /* Release dispatcher lock */ 764 KiReleaseDispatcherLockFromDpcLevel(); 765 766 /* Check if there's an APC state to restore */ 767 if (ApcState->Process) 768 { 769 /* Restore the APC State */ 770 KiMoveApcState(ApcState, &Thread->ApcState); 771 } 772 else 773 { 774 /* The ApcState parameter is useless, so use the saved data and reset it */ 775 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 776 Thread->SavedApcState.Process = NULL; 777 Thread->ApcStateIndex = OriginalApcEnvironment; 778 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 779 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 780 } 781 782 /* Release lock */ 783 KiReleaseApcLockFromDpcLevel(&ApcLock); 784 785 /* Swap Processes */ 786 KiSwapProcess(Thread->ApcState.Process, Process); 787 788 /* Exit the dispatcher */ 789 KiExitDispatcher(ApcLock.OldIrql); 790 791 /* Check if we have pending APCs */ 792 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 793 { 794 /* What do you know, we do! Request them to be delivered */ 795 Thread->ApcState.KernelApcPending = TRUE; 796 HalRequestSoftwareInterrupt(APC_LEVEL); 797 } 798 } 799 800 /* 801 * @implemented 802 */ 803 ULONG 804 NTAPI 805 KeQueryRuntimeProcess(IN PKPROCESS Process, 806 OUT PULONG UserTime) 807 { 808 ULONG TotalUser, TotalKernel; 809 KLOCK_QUEUE_HANDLE ProcessLock; 810 PLIST_ENTRY NextEntry, ListHead; 811 PKTHREAD Thread; 812 813 ASSERT_PROCESS(Process); 814 815 /* Initialize user and kernel times */ 816 TotalUser = Process->UserTime; 817 TotalKernel = Process->KernelTime; 818 819 /* Lock the process */ 820 KiAcquireProcessLock(Process, &ProcessLock); 821 822 /* Loop all child threads and sum up their times */ 823 ListHead = &Process->ThreadListHead; 824 NextEntry = ListHead->Flink; 825 while (ListHead != NextEntry) 826 { 827 /* Get the thread */ 828 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 829 830 /* Sum up times */ 831 TotalKernel += Thread->KernelTime; 832 TotalUser += Thread->UserTime; 833 834 /* Go to the next one */ 835 NextEntry = NextEntry->Flink; 836 } 837 838 /* Release lock */ 839 KiReleaseProcessLock(&ProcessLock); 840 841 /* Return the user time */ 842 *UserTime = TotalUser; 843 844 /* Return the kernel time */ 845 return TotalKernel; 846 } 847 848 /* 849 * @implemented 850 */ 851 BOOLEAN 852 NTAPI 853 KeAddSystemServiceTable(IN PULONG_PTR Base, 854 IN PULONG Count OPTIONAL, 855 IN ULONG Limit, 856 IN PUCHAR Number, 857 IN ULONG Index) 858 { 859 PAGED_CODE(); 860 861 /* Check if descriptor table entry is free */ 862 if ((Index > SSDT_MAX_ENTRIES - 1) || 863 (KeServiceDescriptorTable[Index].Base) || 864 (KeServiceDescriptorTableShadow[Index].Base)) 865 { 866 /* It's not, fail */ 867 return FALSE; 868 } 869 870 /* Initialize the shadow service descriptor table */ 871 KeServiceDescriptorTableShadow[Index].Base = Base; 872 KeServiceDescriptorTableShadow[Index].Limit = Limit; 873 KeServiceDescriptorTableShadow[Index].Number = Number; 874 KeServiceDescriptorTableShadow[Index].Count = Count; 875 return TRUE; 876 } 877 878 /* 879 * @implemented 880 */ 881 BOOLEAN 882 NTAPI 883 KeRemoveSystemServiceTable(IN ULONG Index) 884 { 885 PAGED_CODE(); 886 887 /* Make sure the Index is valid */ 888 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE; 889 890 /* Is there a Normal Descriptor Table? */ 891 if (!KeServiceDescriptorTable[Index].Base) 892 { 893 /* Not with the index, is there a shadow at least? */ 894 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE; 895 } 896 897 /* Now clear from the Shadow Table. */ 898 KeServiceDescriptorTableShadow[Index].Base = NULL; 899 KeServiceDescriptorTableShadow[Index].Number = NULL; 900 KeServiceDescriptorTableShadow[Index].Limit = 0; 901 KeServiceDescriptorTableShadow[Index].Count = NULL; 902 903 /* Check if we should clean from the Master one too */ 904 if (Index == 1) 905 { 906 KeServiceDescriptorTable[Index].Base = NULL; 907 KeServiceDescriptorTable[Index].Number = NULL; 908 KeServiceDescriptorTable[Index].Limit = 0; 909 KeServiceDescriptorTable[Index].Count = NULL; 910 } 911 912 /* Return success */ 913 return TRUE; 914 } 915 /* EOF */ 916