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 /* 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 KiReleaseDispatcherLockFromSynchLevel(); 511 512 /* Release the process lock */ 513 KiReleaseProcessLockFromSynchLevel(&ProcessLock); 514 KiExitDispatcher(ProcessLock.OldIrql); 515 516 /* Return previous priority */ 517 return OldPriority; 518 } 519 520 VOID 521 NTAPI 522 KeQueryValuesProcess(IN PKPROCESS Process, 523 PPROCESS_VALUES Values) 524 { 525 PEPROCESS EProcess; 526 PLIST_ENTRY NextEntry; 527 ULONG TotalKernel, TotalUser; 528 KLOCK_QUEUE_HANDLE ProcessLock; 529 530 ASSERT_PROCESS(Process); 531 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 532 533 /* Lock the process */ 534 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 535 536 /* Initialize user and kernel times */ 537 TotalKernel = Process->KernelTime; 538 TotalUser = Process->UserTime; 539 540 /* Copy the IO_COUNTERS from the process */ 541 EProcess = (PEPROCESS)Process; 542 Values->IoInfo.ReadOperationCount = EProcess->ReadOperationCount.QuadPart; 543 Values->IoInfo.WriteOperationCount = EProcess->WriteOperationCount.QuadPart; 544 Values->IoInfo.OtherOperationCount = EProcess->OtherOperationCount.QuadPart; 545 Values->IoInfo.ReadTransferCount = EProcess->ReadTransferCount.QuadPart; 546 Values->IoInfo.WriteTransferCount = EProcess->WriteTransferCount.QuadPart; 547 Values->IoInfo.OtherTransferCount = EProcess->OtherTransferCount.QuadPart; 548 549 /* Loop all child threads and sum up their times */ 550 for (NextEntry = Process->ThreadListHead.Flink; 551 NextEntry != &Process->ThreadListHead; 552 NextEntry = NextEntry->Flink) 553 { 554 PKTHREAD Thread; 555 556 /* Get the thread */ 557 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 558 559 /* Sum up times */ 560 TotalKernel += Thread->KernelTime; 561 TotalUser += Thread->UserTime; 562 } 563 564 /* Release the process lock */ 565 KiReleaseProcessLock(&ProcessLock); 566 567 /* Compute total times */ 568 Values->TotalKernelTime.QuadPart = TotalKernel * (LONGLONG)KeMaximumIncrement; 569 Values->TotalUserTime.QuadPart = TotalUser * (LONGLONG)KeMaximumIncrement; 570 } 571 572 /* PUBLIC FUNCTIONS **********************************************************/ 573 574 /* 575 * @implemented 576 */ 577 VOID 578 NTAPI 579 KeAttachProcess(IN PKPROCESS Process) 580 { 581 KLOCK_QUEUE_HANDLE ApcLock; 582 PKTHREAD Thread = KeGetCurrentThread(); 583 ASSERT_PROCESS(Process); 584 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 585 586 /* Check if we're already in that process */ 587 if (Thread->ApcState.Process == Process) return; 588 589 /* Check if a DPC is executing or if we're already attached */ 590 if ((Thread->ApcStateIndex != OriginalApcEnvironment) || 591 (KeIsExecutingDpc())) 592 { 593 /* Invalid attempt */ 594 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 595 (ULONG_PTR)Process, 596 (ULONG_PTR)Thread->ApcState.Process, 597 Thread->ApcStateIndex, 598 KeIsExecutingDpc()); 599 } 600 else 601 { 602 /* Acquire APC Lock */ 603 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 604 605 /* Acquire the dispatcher lock */ 606 KiAcquireDispatcherLockAtSynchLevel(); 607 608 /* Legit attach attempt: do it! */ 609 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 610 } 611 } 612 613 /* 614 * @implemented 615 */ 616 VOID 617 NTAPI 618 KeDetachProcess(VOID) 619 { 620 PKTHREAD Thread = KeGetCurrentThread(); 621 KLOCK_QUEUE_HANDLE ApcLock; 622 PKPROCESS Process; 623 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 624 625 /* Check if it's attached */ 626 if (Thread->ApcStateIndex == OriginalApcEnvironment) return; 627 628 /* Acquire APC Lock */ 629 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 630 631 /* Check for invalid attach attempts */ 632 if ((Thread->ApcState.KernelApcInProgress) || 633 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 634 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 635 { 636 /* Crash the system */ 637 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 638 } 639 640 /* Get the process */ 641 Process = Thread->ApcState.Process; 642 643 /* Acquire dispatcher lock */ 644 KiAcquireDispatcherLockAtSynchLevel(); 645 646 /* Decrease the stack count */ 647 ASSERT(Process->StackCount != 0); 648 ASSERT(Process->State == ProcessInMemory); 649 Process->StackCount--; 650 651 /* Check if we can swap the process out */ 652 if (!Process->StackCount) 653 { 654 /* FIXME: Swap the process out */ 655 } 656 657 /* Release dispatcher lock */ 658 KiReleaseDispatcherLockFromSynchLevel(); 659 660 /* Restore the APC State */ 661 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 662 Thread->SavedApcState.Process = NULL; 663 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 664 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 665 Thread->ApcStateIndex = OriginalApcEnvironment; 666 667 /* Release lock */ 668 KiReleaseApcLockFromSynchLevel(&ApcLock); 669 670 /* Swap Processes */ 671 KiSwapProcess(Thread->ApcState.Process, Process); 672 673 /* Exit the dispatcher */ 674 KiExitDispatcher(ApcLock.OldIrql); 675 676 /* Check if we have pending APCs */ 677 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 678 { 679 /* What do you know, we do! Request them to be delivered */ 680 Thread->ApcState.KernelApcPending = TRUE; 681 HalRequestSoftwareInterrupt(APC_LEVEL); 682 } 683 } 684 685 /* 686 * @implemented 687 */ 688 BOOLEAN 689 NTAPI 690 KeIsAttachedProcess(VOID) 691 { 692 /* Return the APC State */ 693 return KeGetCurrentThread()->ApcStateIndex; 694 } 695 696 /* 697 * @implemented 698 */ 699 VOID 700 NTAPI 701 KeStackAttachProcess(IN PKPROCESS Process, 702 OUT PRKAPC_STATE ApcState) 703 { 704 KLOCK_QUEUE_HANDLE ApcLock; 705 PKTHREAD Thread = KeGetCurrentThread(); 706 ASSERT_PROCESS(Process); 707 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 708 709 /* Crash system if DPC is being executed! */ 710 if (KeIsExecutingDpc()) 711 { 712 /* Executing a DPC, crash! */ 713 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 714 (ULONG_PTR)Process, 715 (ULONG_PTR)Thread->ApcState.Process, 716 Thread->ApcStateIndex, 717 KeIsExecutingDpc()); 718 } 719 720 /* Check if we are already in the target process */ 721 if (Thread->ApcState.Process == Process) 722 { 723 /* Set magic value so we don't crash later when detaching */ 724 ApcState->Process = (PKPROCESS)1; 725 return; 726 } 727 728 /* Acquire APC Lock */ 729 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 730 731 /* Acquire dispatcher lock */ 732 KiAcquireDispatcherLockAtSynchLevel(); 733 734 /* Check if the Current Thread is already attached */ 735 if (Thread->ApcStateIndex != OriginalApcEnvironment) 736 { 737 /* We're already attached, so save the APC State into what we got */ 738 KiAttachProcess(Thread, Process, &ApcLock, ApcState); 739 } 740 else 741 { 742 /* We're not attached, so save the APC State into SavedApcState */ 743 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 744 ApcState->Process = NULL; 745 } 746 } 747 748 /* 749 * @implemented 750 */ 751 VOID 752 NTAPI 753 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) 754 { 755 KLOCK_QUEUE_HANDLE ApcLock; 756 PKTHREAD Thread = KeGetCurrentThread(); 757 PKPROCESS Process; 758 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 759 760 /* Check for magic value meaning we were already in the same process */ 761 if (ApcState->Process == (PKPROCESS)1) return; 762 763 /* Loop to make sure no APCs are pending */ 764 for (;;) 765 { 766 /* Acquire APC Lock */ 767 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); 768 769 /* Check if a kernel APC is pending */ 770 if (Thread->ApcState.KernelApcPending) 771 { 772 /* Check if kernel APC should be delivered */ 773 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL)) 774 { 775 /* Release the APC lock so that the APC can be delivered */ 776 KiReleaseApcLock(&ApcLock); 777 continue; 778 } 779 } 780 781 /* Otherwise, break out */ 782 break; 783 } 784 785 /* 786 * Check if the process isn't attacked, or has a Kernel APC in progress 787 * or has pending APC of any kind. 788 */ 789 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || 790 (Thread->ApcState.KernelApcInProgress) || 791 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 792 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 793 { 794 /* Bugcheck the system */ 795 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 796 } 797 798 /* Get the process */ 799 Process = Thread->ApcState.Process; 800 801 /* Acquire dispatcher lock */ 802 KiAcquireDispatcherLockAtSynchLevel(); 803 804 /* Decrease the stack count */ 805 ASSERT(Process->StackCount != 0); 806 ASSERT(Process->State == ProcessInMemory); 807 Process->StackCount--; 808 809 /* Check if we can swap the process out */ 810 if (!Process->StackCount) 811 { 812 /* FIXME: Swap the process out */ 813 } 814 815 /* Release dispatcher lock */ 816 KiReleaseDispatcherLockFromSynchLevel(); 817 818 /* Check if there's an APC state to restore */ 819 if (ApcState->Process) 820 { 821 /* Restore the APC State */ 822 KiMoveApcState(ApcState, &Thread->ApcState); 823 } 824 else 825 { 826 /* The ApcState parameter is useless, so use the saved data and reset it */ 827 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 828 Thread->SavedApcState.Process = NULL; 829 Thread->ApcStateIndex = OriginalApcEnvironment; 830 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 831 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 832 } 833 834 /* Release lock */ 835 KiReleaseApcLockFromSynchLevel(&ApcLock); 836 837 /* Swap Processes */ 838 KiSwapProcess(Thread->ApcState.Process, Process); 839 840 /* Exit the dispatcher */ 841 KiExitDispatcher(ApcLock.OldIrql); 842 843 /* Check if we have pending APCs */ 844 if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) 845 { 846 /* What do you know, we do! Request them to be delivered */ 847 Thread->ApcState.KernelApcPending = TRUE; 848 HalRequestSoftwareInterrupt(APC_LEVEL); 849 } 850 } 851 852 /* 853 * @implemented 854 */ 855 ULONG 856 NTAPI 857 KeQueryRuntimeProcess(IN PKPROCESS Process, 858 OUT PULONG UserTime) 859 { 860 ULONG TotalUser, TotalKernel; 861 KLOCK_QUEUE_HANDLE ProcessLock; 862 PLIST_ENTRY NextEntry, ListHead; 863 PKTHREAD Thread; 864 865 ASSERT_PROCESS(Process); 866 867 /* Initialize user and kernel times */ 868 TotalUser = Process->UserTime; 869 TotalKernel = Process->KernelTime; 870 871 /* Lock the process */ 872 KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); 873 874 /* Loop all child threads and sum up their times */ 875 ListHead = &Process->ThreadListHead; 876 NextEntry = ListHead->Flink; 877 while (ListHead != NextEntry) 878 { 879 /* Get the thread */ 880 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 881 882 /* Sum up times */ 883 TotalKernel += Thread->KernelTime; 884 TotalUser += Thread->UserTime; 885 886 /* Go to the next one */ 887 NextEntry = NextEntry->Flink; 888 } 889 890 /* Release lock */ 891 KiReleaseProcessLock(&ProcessLock); 892 893 /* Return the user time */ 894 *UserTime = TotalUser; 895 896 /* Return the kernel time */ 897 return TotalKernel; 898 } 899 900 /* 901 * @implemented 902 */ 903 BOOLEAN 904 NTAPI 905 KeAddSystemServiceTable(IN PULONG_PTR Base, 906 IN PULONG Count OPTIONAL, 907 IN ULONG Limit, 908 IN PUCHAR Number, 909 IN ULONG Index) 910 { 911 PAGED_CODE(); 912 913 /* Check if descriptor table entry is free */ 914 if ((Index > SSDT_MAX_ENTRIES - 1) || 915 (KeServiceDescriptorTable[Index].Base) || 916 (KeServiceDescriptorTableShadow[Index].Base)) 917 { 918 /* It's not, fail */ 919 return FALSE; 920 } 921 922 /* Initialize the shadow service descriptor table */ 923 KeServiceDescriptorTableShadow[Index].Base = Base; 924 KeServiceDescriptorTableShadow[Index].Limit = Limit; 925 KeServiceDescriptorTableShadow[Index].Number = Number; 926 KeServiceDescriptorTableShadow[Index].Count = Count; 927 return TRUE; 928 } 929 930 /* 931 * @implemented 932 */ 933 BOOLEAN 934 NTAPI 935 KeRemoveSystemServiceTable(IN ULONG Index) 936 { 937 PAGED_CODE(); 938 939 /* Make sure the Index is valid */ 940 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE; 941 942 /* Is there a Normal Descriptor Table? */ 943 if (!KeServiceDescriptorTable[Index].Base) 944 { 945 /* Not with the index, is there a shadow at least? */ 946 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE; 947 } 948 949 /* Now clear from the Shadow Table. */ 950 KeServiceDescriptorTableShadow[Index].Base = NULL; 951 KeServiceDescriptorTableShadow[Index].Number = NULL; 952 KeServiceDescriptorTableShadow[Index].Limit = 0; 953 KeServiceDescriptorTableShadow[Index].Count = NULL; 954 955 /* Check if we should clean from the Master one too */ 956 if (Index == 1) 957 { 958 KeServiceDescriptorTable[Index].Base = NULL; 959 KeServiceDescriptorTable[Index].Number = NULL; 960 KeServiceDescriptorTable[Index].Limit = 0; 961 KeServiceDescriptorTable[Index].Count = NULL; 962 } 963 964 /* Return success */ 965 return TRUE; 966 } 967 /* EOF */ 968