2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/process.c
5 * PURPOSE: Attaching/Detaching and System Call Tables
7 * PROGRAMMERS: Alex Ionescu (Implemented Attach/Detach and KeRemoveSystemServiceTable)
8 * Gregor Anich (Bugfixes to Attach Functions)
11 /* INCLUDES *****************************************************************/
14 #include <internal/napi.h>
16 #include <internal/debug.h>
18 /* GLOBALS *****************************************************************/
20 KSERVICE_TABLE_DESCRIPTOR
22 KeServiceDescriptorTable
[SSDT_MAX_ENTRIES
] = {
23 { MainSSDT
, NULL
, NUMBER_OF_SYSCALLS
, MainSSPT
},
24 { NULL
, NULL
, 0, NULL
},
25 { NULL
, NULL
, 0, NULL
},
26 { NULL
, NULL
, 0, NULL
}
29 KSERVICE_TABLE_DESCRIPTOR
30 KeServiceDescriptorTableShadow
[SSDT_MAX_ENTRIES
] = {
31 { MainSSDT
, NULL
, NUMBER_OF_SYSCALLS
, MainSSPT
},
32 { NULL
, NULL
, 0, NULL
},
33 { NULL
, NULL
, 0, NULL
},
34 { NULL
, NULL
, 0, NULL
}
37 /* FUNCTIONS *****************************************************************/
40 UpdatePageDirs(PKTHREAD Thread
, PKPROCESS Process
)
43 * The stack and the thread structure of the current process may be
44 * located in a page which is not present in the page directory of
45 * the process we're attaching to. That would lead to a page fault
46 * when this function returns. However, since the processor can't
47 * call the page fault handler 'cause it can't push EIP on the stack,
48 * this will show up as a stack fault which will crash the entire system.
49 * To prevent this, make sure the page directory of the process we're
50 * attaching to is up-to-date.
52 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
53 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
57 * FUNCTION: Returns a pointer to the current process
61 KeGetCurrentProcess(VOID
)
63 return(&(PsGetCurrentProcess()->Pcb
));
68 KeInitializeProcess(PKPROCESS Process
,
71 LARGE_INTEGER DirectoryTableBase
)
73 DPRINT("KeInitializeProcess. Process: %x, DirectoryTableBase: %x\n", Process
, DirectoryTableBase
);
75 /* Initialize the Dispatcher Header */
76 KeInitializeDispatcherHeader(&Process
->Header
,
81 /* Initialize Scheduler Data, Disable Alignment Faults and Set the PDE */
82 Process
->Affinity
= Affinity
;
83 Process
->BasePriority
= Priority
;
84 Process
->QuantumReset
= 6;
85 Process
->DirectoryTableBase
= DirectoryTableBase
;
86 Process
->AutoAlignment
= TRUE
;
87 Process
->IopmOffset
= 0xFFFF;
88 Process
->State
= PROCESS_STATE_ACTIVE
;
90 /* Initialize the Thread List */
91 InitializeListHead(&Process
->ThreadListHead
);
92 KeInitializeSpinLock(&Process
->ProcessLock
);
93 DPRINT("The Process has now been initalized with the Kernel\n");
98 KeSetProcess(PKPROCESS Process
,
104 /* Lock Dispatcher */
105 OldIrql
= KeAcquireDispatcherDatabaseLock();
108 OldState
= Process
->Header
.SignalState
;
110 /* Signal the Process */
111 Process
->Header
.SignalState
= TRUE
;
112 if ((OldState
== 0) && IsListEmpty(&Process
->Header
.WaitListHead
) != TRUE
) {
115 KiWaitTest((PVOID
)Process
, Increment
);
118 /* Release Dispatcher Database */
119 KeReleaseDispatcherDatabaseLock(OldIrql
);
121 /* Return the previous State */
130 KeAttachProcess(PKPROCESS Process
)
133 PKTHREAD Thread
= KeGetCurrentThread();
135 DPRINT("KeAttachProcess: %x\n", Process
);
137 /* Make sure that we are in the right page directory */
138 UpdatePageDirs(Thread
, Process
);
140 /* Lock Dispatcher */
141 OldIrql
= KeAcquireDispatcherDatabaseLock();
142 KeAcquireSpinLockAtDpcLevel(&Thread
->ApcQueueLock
);
144 /* Crash system if DPC is being executed! */
145 if (KeIsExecutingDpc()) {
147 DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
148 KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT
);
151 /* Check if the Target Process is already attached */
152 if (Thread
->ApcState
.Process
== Process
|| Thread
->ApcStateIndex
!= OriginalApcEnvironment
) {
154 DPRINT("Process already Attached. Exitting\n");
155 KeReleaseSpinLockFromDpcLevel(&Thread
->ApcQueueLock
);
156 KeReleaseDispatcherDatabaseLock(OldIrql
);
159 KiAttachProcess(Thread
, Process
, OldIrql
, &Thread
->SavedApcState
);
165 KiAttachProcess(PKTHREAD Thread
, PKPROCESS Process
, KIRQL ApcLock
, PRKAPC_STATE SavedApcState
)
168 DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n", Thread
, Process
, SavedApcState
);
170 /* Increase Stack Count */
171 Process
->StackCount
++;
173 /* Swap the APC Environment */
174 KiMoveApcState(&Thread
->ApcState
, SavedApcState
);
176 /* Reinitialize Apc State */
177 InitializeListHead(&Thread
->ApcState
.ApcListHead
[KernelMode
]);
178 InitializeListHead(&Thread
->ApcState
.ApcListHead
[UserMode
]);
179 Thread
->ApcState
.Process
= Process
;
180 Thread
->ApcState
.KernelApcInProgress
= FALSE
;
181 Thread
->ApcState
.KernelApcPending
= FALSE
;
182 Thread
->ApcState
.UserApcPending
= FALSE
;
184 /* Update Environment Pointers if needed*/
185 if (SavedApcState
== &Thread
->SavedApcState
) {
187 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->SavedApcState
;
188 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->ApcState
;
189 Thread
->ApcStateIndex
= AttachedApcEnvironment
;
192 /* Swap the Processes */
193 DPRINT("Swapping\n");
194 KiSwapProcess(Process
, SavedApcState
->Process
);
196 /* Return to old IRQL*/
197 KeReleaseSpinLockFromDpcLevel(&Thread
->ApcQueueLock
);
198 KeReleaseDispatcherDatabaseLock(ApcLock
);
200 DPRINT("KiAttachProcess Completed Sucesfully\n");
205 KiSwapProcess(PKPROCESS NewProcess
,
206 PKPROCESS OldProcess
)
208 /* FIXME: Write this in ASM. Much easier */
209 DPRINT("Switching CR3 to: %x\n", NewProcess
->DirectoryTableBase
.u
.LowPart
);
210 Ke386SetPageTableDirectory(NewProcess
->DirectoryTableBase
.u
.LowPart
);
218 KeIsAttachedProcess(VOID
)
220 /* Return the APC State */
221 return KeGetCurrentThread()->ApcStateIndex
;
229 KeStackAttachProcess(IN PKPROCESS Process
,
230 OUT PRKAPC_STATE ApcState
)
233 PKTHREAD Thread
= KeGetCurrentThread();
235 /* Make sure that we are in the right page directory */
236 UpdatePageDirs(Thread
, Process
);
238 OldIrql
= KeAcquireDispatcherDatabaseLock();
239 KeAcquireSpinLockAtDpcLevel(&Thread
->ApcQueueLock
);
241 /* Crash system if DPC is being executed! */
242 if (KeIsExecutingDpc()) {
244 DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
245 KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT
);
248 /* Check if the Target Process is already attached */
249 if (Thread
->ApcState
.Process
== Process
) {
251 ApcState
->Process
= (PKPROCESS
)1; /* Meaning already attached to the same Process */
255 /* Check if the Current Thread is already attached and call the Internal Function*/
256 if (Thread
->ApcStateIndex
!= OriginalApcEnvironment
) {
258 KiAttachProcess(Thread
, Process
, OldIrql
, ApcState
);
261 KiAttachProcess(Thread
, Process
, OldIrql
, &Thread
->SavedApcState
);
262 ApcState
->Process
= NULL
;
271 KeDetachProcess (VOID
)
276 DPRINT("KeDetachProcess()\n");
278 /* Get Current Thread and Lock */
279 Thread
= KeGetCurrentThread();
280 OldIrql
= KeAcquireDispatcherDatabaseLock();
281 KeAcquireSpinLockAtDpcLevel(&Thread
->ApcQueueLock
);
283 /* Check if it's attached */
284 DPRINT("Current ApcStateIndex: %x\n", Thread
->ApcStateIndex
);
286 if (Thread
->ApcStateIndex
== OriginalApcEnvironment
) {
288 DPRINT1("Invalid detach (thread was not attached)\n");
289 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT
);
292 /* Decrease Stack Count */
293 Thread
->ApcState
.Process
->StackCount
--;
295 /* Restore the APC State */
296 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
297 Thread
->SavedApcState
.Process
= NULL
;
298 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
299 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
300 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
303 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
305 /* Unlock Dispatcher */
306 KeReleaseSpinLockFromDpcLevel(&Thread
->ApcQueueLock
);
307 KeReleaseDispatcherDatabaseLock(OldIrql
);
315 KeUnstackDetachProcess (
316 IN PRKAPC_STATE ApcState
323 * If the special "We tried to attach to the process already being
324 * attached to" flag is there, don't do anything
326 if (ApcState
->Process
== (PKPROCESS
)1) return;
328 Thread
= KeGetCurrentThread();
329 OldIrql
= KeAcquireDispatcherDatabaseLock();
330 KeAcquireSpinLockAtDpcLevel(&Thread
->ApcQueueLock
);
332 /* Sorry Buddy, can't help you if you've got APCs or just aren't attached */
333 if ((Thread
->ApcStateIndex
== OriginalApcEnvironment
) || (Thread
->ApcState
.KernelApcInProgress
)) {
335 DPRINT1("Invalid detach (Thread not Attached, or Kernel APC in Progress!)\n");
336 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT
);
339 /* Restore the Old APC State if a Process was present */
340 if (ApcState
->Process
) {
342 KiMoveApcState(ApcState
, &Thread
->ApcState
);
346 /* The ApcState parameter is useless, so use the saved data and reset it */
347 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
348 Thread
->SavedApcState
.Process
= NULL
;
349 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
350 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
351 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
355 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
357 /* Return to old IRQL*/
358 KeReleaseSpinLockFromDpcLevel(&Thread
->ApcQueueLock
);
359 KeReleaseDispatcherDatabaseLock(OldIrql
);
367 KeAddSystemServiceTable(PULONG_PTR Base
,
368 PULONG Count OPTIONAL
,
373 /* Check if descriptor table entry is free */
374 if ((Index
> SSDT_MAX_ENTRIES
- 1) ||
375 (KeServiceDescriptorTable
[Index
].Base
) ||
376 (KeServiceDescriptorTableShadow
[Index
].Base
))
381 /* Initialize the shadow service descriptor table */
382 KeServiceDescriptorTableShadow
[Index
].Base
= Base
;
383 KeServiceDescriptorTableShadow
[Index
].Limit
= Limit
;
384 KeServiceDescriptorTableShadow
[Index
].Number
= Number
;
385 KeServiceDescriptorTableShadow
[Index
].Count
= Count
;
395 KeRemoveSystemServiceTable(IN ULONG Index
)
397 /* Make sure the Index is valid */
398 if (Index
> SSDT_MAX_ENTRIES
- 1) return FALSE
;
400 /* Is there a Normal Descriptor Table? */
401 if (!KeServiceDescriptorTable
[Index
].Base
)
403 /* Not with the index, is there a shadow at least? */
404 if (!KeServiceDescriptorTableShadow
[Index
].Base
) return FALSE
;
407 /* Now clear from the Shadow Table. */
408 KeServiceDescriptorTableShadow
[Index
].Base
= NULL
;
409 KeServiceDescriptorTableShadow
[Index
].Number
= NULL
;
410 KeServiceDescriptorTableShadow
[Index
].Limit
= 0;
411 KeServiceDescriptorTableShadow
[Index
].Count
= NULL
;
413 /* Check if we should clean from the Master one too */
416 KeServiceDescriptorTable
[Index
].Base
= NULL
;
417 KeServiceDescriptorTable
[Index
].Number
= NULL
;
418 KeServiceDescriptorTable
[Index
].Limit
= 0;
419 KeServiceDescriptorTable
[Index
].Count
= NULL
;