Create the AHCI branch for Aman's work
[reactos.git] / ntoskrnl / ke / procobj.c
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 */