KD System Rewrite:
[reactos.git] / reactos / ntoskrnl / ke / process.c
1 /*
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
6 *
7 * PROGRAMMERS: Alex Ionescu (Implemented Attach/Detach and KeRemoveSystemServiceTable)
8 * Gregor Anich (Bugfixes to Attach Functions)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #include <ntdll/napi.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *****************************************************************/
19
20 SSDT_ENTRY
21 __declspec(dllexport)
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 }
27 };
28
29 SSDT_ENTRY
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 }
35 };
36
37 /* FUNCTIONS *****************************************************************/
38
39 static inline void
40 UpdatePageDirs(PKTHREAD Thread, PKPROCESS Process)
41 {
42 /*
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.
51 */
52 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
53 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
54 }
55
56 /*
57 * FUNCTION: Returns a pointer to the current process
58 */
59 PKPROCESS
60 STDCALL
61 KeGetCurrentProcess(VOID)
62 {
63 return(&(PsGetCurrentProcess()->Pcb));
64 }
65
66 VOID
67 STDCALL
68 KeInitializeProcess(PKPROCESS Process,
69 KPRIORITY Priority,
70 KAFFINITY Affinity,
71 LARGE_INTEGER DirectoryTableBase)
72 {
73 DPRINT("KeInitializeProcess. Process: %x, DirectoryTableBase: %x\n", Process, DirectoryTableBase);
74
75 /* Initialize the Dispatcher Header */
76 KeInitializeDispatcherHeader(&Process->DispatcherHeader,
77 ProcessObject,
78 sizeof(KPROCESS),
79 FALSE);
80
81 /* Initialize Scheduler Data, Disable Alignment Faults and Set the PDE */
82 Process->Affinity = Affinity;
83 Process->BasePriority = Priority;
84 Process->ThreadQuantum = 6;
85 Process->DirectoryTableBase = DirectoryTableBase;
86 Process->AutoAlignment = TRUE;
87 Process->IopmOffset = 0xFFFF;
88 Process->State = PROCESS_STATE_ACTIVE;
89
90 /* Initialize the Thread List */
91 InitializeListHead(&Process->ThreadListHead);
92 DPRINT("The Process has now been initalized with the Kernel\n");
93 }
94
95 ULONG
96 STDCALL
97 KeSetProcess(PKPROCESS Process,
98 KPRIORITY Increment)
99 {
100 KIRQL OldIrql;
101 ULONG OldState;
102
103 /* Lock Dispatcher */
104 OldIrql = KeAcquireDispatcherDatabaseLock();
105
106 /* Get Old State */
107 OldState = Process->DispatcherHeader.SignalState;
108
109 /* Signal the Process */
110 Process->DispatcherHeader.SignalState = TRUE;
111 if ((OldState == 0) && IsListEmpty(&Process->DispatcherHeader.WaitListHead) != TRUE) {
112
113 /* Satisfy waits */
114 KiWaitTest((PVOID)Process, Increment);
115 }
116
117 /* Release Dispatcher Database */
118 KeReleaseDispatcherDatabaseLock(OldIrql);
119
120 /* Return the previous State */
121 return OldState;
122 }
123
124 /*
125 * @implemented
126 */
127 VOID
128 STDCALL
129 KeAttachProcess(PKPROCESS Process)
130 {
131 KIRQL OldIrql;
132 PKTHREAD Thread = KeGetCurrentThread();
133
134 DPRINT("KeAttachProcess: %x\n", Process);
135
136 /* Make sure that we are in the right page directory */
137 UpdatePageDirs(Thread, Process);
138
139 /* Lock Dispatcher */
140 OldIrql = KeAcquireDispatcherDatabaseLock();
141
142 /* Crash system if DPC is being executed! */
143 if (KeIsExecutingDpc()) {
144
145 DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
146 KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT);
147 }
148
149 /* Check if the Target Process is already attached */
150 if (Thread->ApcState.Process == Process || Thread->ApcStateIndex != OriginalApcEnvironment) {
151
152 DPRINT("Process already Attached. Exitting\n");
153 KeReleaseDispatcherDatabaseLock(OldIrql);
154 } else {
155
156 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
157 }
158 }
159
160 VOID
161 STDCALL
162 KiAttachProcess(PKTHREAD Thread, PKPROCESS Process, KIRQL ApcLock, PRKAPC_STATE SavedApcState)
163 {
164
165 DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n", Thread, Process, SavedApcState);
166
167 /* Increase Stack Count */
168 Process->StackCount++;
169
170 /* Swap the APC Environment */
171 KiMoveApcState(&Thread->ApcState, SavedApcState);
172
173 /* Reinitialize Apc State */
174 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
175 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
176 Thread->ApcState.Process = Process;
177 Thread->ApcState.KernelApcInProgress = FALSE;
178 Thread->ApcState.KernelApcPending = FALSE;
179 Thread->ApcState.UserApcPending = FALSE;
180
181 /* Update Environment Pointers if needed*/
182 if (SavedApcState == &Thread->SavedApcState) {
183
184 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->SavedApcState;
185 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState;
186 Thread->ApcStateIndex = AttachedApcEnvironment;
187 }
188
189 /* Swap the Processes */
190 DPRINT("Swapping\n");
191 KiSwapProcess(Process, SavedApcState->Process);
192
193 /* Return to old IRQL*/
194 KeReleaseDispatcherDatabaseLock(ApcLock);
195
196 DPRINT("KiAttachProcess Completed Sucesfully\n");
197 }
198
199 VOID
200 STDCALL
201 KiSwapProcess(PKPROCESS NewProcess, PKPROCESS OldProcess)
202 {
203 //PKPCR Pcr = KeGetCurrentKpcr();
204
205 /* Do they have an LDT? */
206 if ((NewProcess->LdtDescriptor) || (OldProcess->LdtDescriptor)) {
207
208 /* FIXME : SWitch GDT/IDT */
209 }
210 DPRINT("Switching CR3 to: %x\n", NewProcess->DirectoryTableBase.u.LowPart);
211 Ke386SetPageTableDirectory(NewProcess->DirectoryTableBase.u.LowPart);
212
213 /* FIXME: Set IopmOffset in TSS */
214 }
215
216 /*
217 * @implemented
218 */
219 BOOLEAN
220 STDCALL
221 KeIsAttachedProcess(VOID)
222 {
223 /* Return the APC State */
224 return KeGetCurrentThread()->ApcStateIndex;
225 }
226
227 /*
228 * @implemented
229 */
230 VOID
231 STDCALL
232 KeStackAttachProcess(IN PKPROCESS Process,
233 OUT PRKAPC_STATE ApcState)
234 {
235 KIRQL OldIrql;
236 PKTHREAD Thread = KeGetCurrentThread();
237
238 /* Make sure that we are in the right page directory */
239 UpdatePageDirs(Thread, Process);
240
241 OldIrql = KeAcquireDispatcherDatabaseLock();
242
243 /* Crash system if DPC is being executed! */
244 if (KeIsExecutingDpc()) {
245
246 DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
247 KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT);
248 }
249
250 /* Check if the Target Process is already attached */
251 if (Thread->ApcState.Process == Process) {
252
253 ApcState->Process = (PKPROCESS)1; /* Meaning already attached to the same Process */
254
255 } else {
256
257 /* Check if the Current Thread is already attached and call the Internal Function*/
258 if (Thread->ApcStateIndex != OriginalApcEnvironment) {
259
260 KiAttachProcess(Thread, Process, OldIrql, ApcState);
261 } else {
262
263 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
264 ApcState->Process = NULL;
265 }
266 }
267 }
268
269 /*
270 * @implemented
271 */
272 VOID STDCALL
273 KeDetachProcess (VOID)
274 {
275 PKTHREAD Thread;
276 KIRQL OldIrql;
277
278 DPRINT("KeDetachProcess()\n");
279
280 /* Get Current Thread and Lock */
281 Thread = KeGetCurrentThread();
282 OldIrql = KeAcquireDispatcherDatabaseLock();
283
284 /* Check if it's attached */
285 DPRINT("Current ApcStateIndex: %x\n", Thread->ApcStateIndex);
286
287 if (Thread->ApcStateIndex == OriginalApcEnvironment) {
288
289 DPRINT1("Invalid detach (thread was not attached)\n");
290 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
291 }
292
293 /* Decrease Stack Count */
294 Thread->ApcState.Process->StackCount--;
295
296 /* Restore the APC State */
297 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
298 Thread->SavedApcState.Process = NULL;
299 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
300 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
301 Thread->ApcStateIndex = OriginalApcEnvironment;
302
303 /* Swap Processes */
304 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
305
306 /* Unlock Dispatcher */
307 KeReleaseDispatcherDatabaseLock(OldIrql);
308 }
309
310 /*
311 * @implemented
312 */
313 VOID
314 STDCALL
315 KeUnstackDetachProcess (
316 IN PRKAPC_STATE ApcState
317 )
318 {
319 KIRQL OldIrql;
320 PKTHREAD Thread;
321
322 /*
323 * If the special "We tried to attach to the process already being
324 * attached to" flag is there, don't do anything
325 */
326 if (ApcState->Process == (PKPROCESS)1) return;
327
328 Thread = KeGetCurrentThread();
329 OldIrql = KeAcquireDispatcherDatabaseLock();
330
331 /* Sorry Buddy, can't help you if you've got APCs or just aren't attached */
332 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || (Thread->ApcState.KernelApcInProgress)) {
333
334 DPRINT1("Invalid detach (Thread not Attached, or Kernel APC in Progress!)\n");
335 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
336 }
337
338 /* Restore the Old APC State if a Process was present */
339 if (ApcState->Process) {
340
341 KiMoveApcState(ApcState, &Thread->ApcState);
342
343 } else {
344
345 /* The ApcState parameter is useless, so use the saved data and reset it */
346 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
347 Thread->SavedApcState.Process = NULL;
348 Thread->ApcStateIndex = OriginalApcEnvironment;
349 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
350 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
351 }
352
353 /* Swap Processes */
354 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
355
356 /* Return to old IRQL*/
357 KeReleaseDispatcherDatabaseLock(OldIrql);
358 }
359
360 /*
361 * @implemented
362 */
363 BOOLEAN STDCALL
364 KeAddSystemServiceTable(PSSDT SSDT,
365 PULONG ServiceCounterTable,
366 ULONG NumberOfServices,
367 PSSPT SSPT,
368 ULONG TableIndex)
369 {
370 /* check if descriptor table entry is free */
371 if ((TableIndex > SSDT_MAX_ENTRIES - 1) ||
372 (KeServiceDescriptorTable[TableIndex].SSDT != NULL) ||
373 (KeServiceDescriptorTableShadow[TableIndex].SSDT != NULL))
374 return FALSE;
375
376 /* initialize the shadow service descriptor table */
377 KeServiceDescriptorTableShadow[TableIndex].SSDT = SSDT;
378 KeServiceDescriptorTableShadow[TableIndex].SSPT = SSPT;
379 KeServiceDescriptorTableShadow[TableIndex].NumberOfServices = NumberOfServices;
380 KeServiceDescriptorTableShadow[TableIndex].ServiceCounterTable = ServiceCounterTable;
381
382 return TRUE;
383 }
384
385 /*
386 * @implemented
387 */
388 BOOLEAN
389 STDCALL
390 KeRemoveSystemServiceTable(IN ULONG TableIndex)
391 {
392 /* Make sure the Index is valid */
393 if (TableIndex > SSDT_MAX_ENTRIES - 1) return FALSE;
394
395 /* Is there a Normal Descriptor Table? */
396 if (!KeServiceDescriptorTable[TableIndex].SSDT) {
397
398 /* Not with the index, is there a shadow at least? */
399 if (!KeServiceDescriptorTableShadow[TableIndex].SSDT) return FALSE;
400 }
401
402 /* Now clear from the Shadow Table. */
403 KeServiceDescriptorTableShadow[TableIndex].SSDT = NULL;
404 KeServiceDescriptorTableShadow[TableIndex].SSPT = NULL;
405 KeServiceDescriptorTableShadow[TableIndex].NumberOfServices = 0;
406 KeServiceDescriptorTableShadow[TableIndex].ServiceCounterTable = NULL;
407
408 /* Check if we should clean from the Master one too */
409 if (TableIndex == 1) {
410
411 KeServiceDescriptorTable[TableIndex].SSDT = NULL;
412 KeServiceDescriptorTable[TableIndex].SSPT = NULL;
413 KeServiceDescriptorTable[TableIndex].NumberOfServices = 0;
414 KeServiceDescriptorTable[TableIndex].ServiceCounterTable = NULL;
415 }
416
417 return TRUE;
418 }
419 /* EOF */