[DRWTSN32] Print some extra exception info
[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 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 KiAcquireProcessLock(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 KiAcquireApcLock(Thread, &ApcLock);
604
605 /* Acquire the dispatcher lock */
606 KiAcquireDispatcherLockAtDpcLevel();
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 KiAcquireApcLock(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 KiAcquireDispatcherLockAtDpcLevel();
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 KiReleaseDispatcherLockFromDpcLevel();
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 KiReleaseApcLockFromDpcLevel(&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 KiAcquireApcLock(Thread, &ApcLock);
730
731 /* Acquire dispatcher lock */
732 KiAcquireDispatcherLockAtDpcLevel();
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 KiAcquireApcLock(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 KiAcquireDispatcherLockAtDpcLevel();
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 KiReleaseDispatcherLockFromDpcLevel();
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 KiReleaseApcLockFromDpcLevel(&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 KiAcquireProcessLock(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 */