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