- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[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: Kernel Process Management and System Call Tables
6 * PROGRAMMERS: Alex Ionescu
7 * Gregor Anich
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #include <internal/napi.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *****************************************************************/
18
19 KSERVICE_TABLE_DESCRIPTOR
20 __declspec(dllexport)
21 KeServiceDescriptorTable[SSDT_MAX_ENTRIES] =
22 {
23 { MainSSDT, NULL, NUMBER_OF_SYSCALLS, MainSSPT },
24 { NULL, NULL, 0, NULL },
25 };
26
27 KSERVICE_TABLE_DESCRIPTOR
28 KeServiceDescriptorTableShadow[SSDT_MAX_ENTRIES] =
29 {
30 { MainSSDT, NULL, NUMBER_OF_SYSCALLS, MainSSPT },
31 { NULL, NULL, 0, NULL },
32 };
33
34 /* FUNCTIONS *****************************************************************/
35
36 PKPROCESS
37 STDCALL
38 KeGetCurrentProcess(VOID)
39 {
40 return(&(PsGetCurrentProcess()->Pcb));
41 }
42
43 static __inline
44 VOID
45 NTAPI
46 UpdatePageDirs(IN PKTHREAD Thread,
47 IN PKPROCESS Process)
48 {
49 /*
50 * The stack and the thread structure of the current process may be
51 * located in a page which is not present in the page directory of
52 * the process we're attaching to. That would lead to a page fault
53 * when this function returns. However, since the processor can't
54 * call the page fault handler 'cause it can't push EIP on the stack,
55 * this will show up as a stack fault which will crash the entire system.
56 * To prevent this, make sure the page directory of the process we're
57 * attaching to is up-to-date.
58 */
59 MmUpdatePageDir((PROS_EPROCESS)Process, (PVOID)Thread->StackLimit, KERNEL_STACK_SIZE);
60 MmUpdatePageDir((PROS_EPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
61 }
62
63 VOID
64 NTAPI
65 KiAttachProcess(PKTHREAD Thread,
66 PKPROCESS Process,
67 KIRQL OldIrql,
68 PRKAPC_STATE SavedApcState)
69 {
70 ASSERT(Process != Thread->ApcState.Process);
71 DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n",
72 Thread, Process, SavedApcState);
73
74 /* Increase Stack Count */
75 Process->StackCount++;
76
77 /* Swap the APC Environment */
78 KiMoveApcState(&Thread->ApcState, SavedApcState);
79
80 /* Reinitialize Apc State */
81 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
82 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
83 Thread->ApcState.Process = Process;
84 Thread->ApcState.KernelApcInProgress = FALSE;
85 Thread->ApcState.KernelApcPending = FALSE;
86 Thread->ApcState.UserApcPending = FALSE;
87
88 /* Update Environment Pointers if needed*/
89 if (SavedApcState == &Thread->SavedApcState)
90 {
91 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->SavedApcState;
92 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState;
93 Thread->ApcStateIndex = AttachedApcEnvironment;
94 }
95
96 /* Check if the process is paged in */
97 if (Process->State == ProcessInMemory)
98 {
99 /* FIXME: Scan the Ready Thread List once new scheduler is in */
100
101 /* Swap the Processes */
102 KiSwapProcess(Process, SavedApcState->Process);
103
104 /* Return to old IRQL*/
105 KeReleaseDispatcherDatabaseLock(OldIrql);
106 }
107 else
108 {
109 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n");
110 DbgBreakPoint();
111 }
112 }
113
114 VOID
115 NTAPI
116 KeInitializeProcess(PKPROCESS Process,
117 KPRIORITY Priority,
118 KAFFINITY Affinity,
119 LARGE_INTEGER DirectoryTableBase)
120 {
121 DPRINT("KeInitializeProcess. Process: %x, DirectoryTableBase: %x\n",
122 Process, DirectoryTableBase);
123
124 /* Initialize the Dispatcher Header */
125 KeInitializeDispatcherHeader(&Process->Header,
126 ProcessObject,
127 sizeof(KPROCESS),
128 FALSE);
129
130 /* Initialize Scheduler Data, Disable Alignment Faults and Set the PDE */
131 Process->Affinity = Affinity;
132 Process->BasePriority = Priority;
133 Process->QuantumReset = 6;
134 Process->DirectoryTableBase = DirectoryTableBase;
135 Process->AutoAlignment = TRUE;
136 Process->IopmOffset = 0xFFFF;
137 Process->State = ProcessInMemory;
138
139 /* Initialize the Thread List */
140 InitializeListHead(&Process->ThreadListHead);
141 KeInitializeSpinLock(&Process->ProcessLock);
142 DPRINT("The Process has now been initalized with the Kernel\n");
143 }
144
145 ULONG
146 NTAPI
147 KeSetProcess(PKPROCESS Process,
148 KPRIORITY Increment)
149 {
150 KIRQL OldIrql;
151 ULONG OldState;
152
153 /* Lock Dispatcher */
154 OldIrql = KeAcquireDispatcherDatabaseLock();
155
156 /* Get Old State */
157 OldState = Process->Header.SignalState;
158
159 /* Signal the Process */
160 Process->Header.SignalState = TRUE;
161 if ((OldState == 0) && IsListEmpty(&Process->Header.WaitListHead) != TRUE)
162 {
163 /* Satisfy waits */
164 KiWaitTest((PVOID)Process, Increment);
165 }
166
167 /* Release Dispatcher Database */
168 KeReleaseDispatcherDatabaseLock(OldIrql);
169
170 /* Return the previous State */
171 return OldState;
172 }
173
174 VOID
175 NTAPI
176 KiSwapProcess(PKPROCESS NewProcess,
177 PKPROCESS OldProcess)
178 {
179 DPRINT("Switching CR3 to: %x\n", NewProcess->DirectoryTableBase.u.LowPart);
180 Ke386SetPageTableDirectory(NewProcess->DirectoryTableBase.u.LowPart);
181 }
182
183 /*
184 * @implemented
185 */
186 VOID
187 NTAPI
188 KeAttachProcess(PKPROCESS Process)
189 {
190 KIRQL OldIrql;
191 PKTHREAD Thread;
192 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
193 DPRINT("KeAttachProcess: %x\n", Process);
194
195 /* Make sure that we are in the right page directory */
196 Thread = KeGetCurrentThread();
197 UpdatePageDirs(Thread, Process);
198
199 /* Lock Dispatcher */
200 OldIrql = KeAcquireDispatcherDatabaseLock();
201
202 /* Check if we're already in that process */
203 if (Thread->ApcState.Process == Process)
204 {
205 /* Unlock the dispatcher, nothing to do */
206 KeReleaseDispatcherDatabaseLock(OldIrql);
207 }
208 else if ((Thread->ApcStateIndex != OriginalApcEnvironment) ||
209 (KeIsExecutingDpc()))
210 {
211 /* Executing a DPC or already attached, crash! */
212 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
213 (ULONG_PTR)Process,
214 (ULONG_PTR)Thread->ApcState.Process,
215 Thread->ApcStateIndex,
216 KeIsExecutingDpc());
217 }
218 else
219 {
220 /* Legit attach attempt: do it! */
221 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
222 }
223 }
224
225 /*
226 * @implemented
227 */
228 VOID
229 NTAPI
230 KeDetachProcess (VOID)
231 {
232 PKTHREAD Thread;
233 KIRQL OldIrql;
234 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
235 DPRINT("KeDetachProcess()\n");
236
237 /* Get Current Thread and lock the dispatcher */
238 Thread = KeGetCurrentThread();
239 OldIrql = KeAcquireDispatcherDatabaseLock();
240
241 /* Check if it's attached */
242 if (Thread->ApcStateIndex != OriginalApcEnvironment)
243 {
244 /* It is, decrease Stack Count */
245 if(!(--Thread->ApcState.Process->StackCount))
246 {
247 /* FIXME: Swap the process out */
248 }
249
250 /* Restore the APC State */
251 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
252 Thread->SavedApcState.Process = NULL;
253 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
254 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
255 Thread->ApcStateIndex = OriginalApcEnvironment;
256
257 /* Check if we have pending APCs */
258 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
259 {
260 /* What do you know, we do! Request them to be delivered */
261 Thread->ApcState.KernelApcPending = TRUE;
262 HalRequestSoftwareInterrupt(APC_LEVEL);
263 }
264
265 /* Swap Processes */
266 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
267 }
268
269 /* Unlock Dispatcher */
270 KeReleaseDispatcherDatabaseLock(OldIrql);
271 }
272
273 /*
274 * @implemented
275 */
276 BOOLEAN
277 NTAPI
278 KeIsAttachedProcess(VOID)
279 {
280 /* Return the APC State */
281 return KeGetCurrentThread()->ApcStateIndex;
282 }
283
284 /*
285 * @implemented
286 */
287 VOID
288 NTAPI
289 KeStackAttachProcess(IN PKPROCESS Process,
290 OUT PRKAPC_STATE ApcState)
291 {
292 KIRQL OldIrql;
293 PKTHREAD Thread;
294 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
295
296 /* Make sure that we are in the right page directory */
297 Thread = KeGetCurrentThread();
298 UpdatePageDirs(Thread, Process);
299
300 /* Acquire the dispatcher lock */
301 OldIrql = KeAcquireDispatcherDatabaseLock();
302
303 /* Crash system if DPC is being executed! */
304 if (KeIsExecutingDpc())
305 {
306 /* Executing a DPC, crash! */
307 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
308 (ULONG_PTR)Process,
309 (ULONG_PTR)Thread->ApcState.Process,
310 Thread->ApcStateIndex,
311 KeIsExecutingDpc());
312 }
313
314 /* Check if we are already in the target process */
315 if (Thread->ApcState.Process == Process)
316 {
317 /* Unlock the dispatcher database */
318 KeReleaseDispatcherDatabaseLock(OldIrql);
319
320 /* Set magic value so we don't crash later when detaching */
321 ApcState->Process = (PKPROCESS)1;
322 }
323 else
324 {
325 /* Check if the Current Thread is already attached */
326 if (Thread->ApcStateIndex != OriginalApcEnvironment)
327 {
328 /* We're already attached, so save the APC State into what we got */
329 KiAttachProcess(Thread, Process, OldIrql, ApcState);
330 }
331 else
332 {
333 /* We're not attached, so save the APC State into SavedApcState */
334 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
335 ApcState->Process = NULL;
336 }
337 }
338 }
339
340 /*
341 * @implemented
342 */
343 VOID
344 NTAPI
345 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
346 {
347 KIRQL OldIrql;
348 PKTHREAD Thread;
349 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
350
351 /* Get the current thread and acquire the dispatcher lock */
352 Thread = KeGetCurrentThread();
353 OldIrql = KeAcquireDispatcherDatabaseLock();
354
355 /* Check for magic value meaning we were already in the same process */
356 if (ApcState->Process != (PKPROCESS)1)
357 {
358 /*
359 * Check if the process isn't attacked, or has a Kernel APC in progress
360 * or has pending APC of any kind.
361 */
362 if ((Thread->ApcStateIndex == OriginalApcEnvironment) ||
363 (Thread->ApcState.KernelApcInProgress) ||
364 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) ||
365 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
366 {
367 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
368 }
369
370 /* Decrease Stack Count */
371 if(!(--Thread->ApcState.Process->StackCount))
372 {
373 /* FIXME: Swap the process out */
374 }
375
376 if (ApcState->Process != NULL)
377 {
378 /* Restore the APC State */
379 KiMoveApcState(ApcState, &Thread->ApcState);
380 }
381 else
382 {
383 /* The ApcState parameter is useless, so use the saved data and reset it */
384 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
385 Thread->SavedApcState.Process = NULL;
386 Thread->ApcStateIndex = OriginalApcEnvironment;
387 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
388 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
389 }
390
391 /* Check if we have pending APCs */
392 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
393 {
394 /* What do you know, we do! Request them to be delivered */
395 Thread->ApcState.KernelApcPending = TRUE;
396 HalRequestSoftwareInterrupt(APC_LEVEL);
397 }
398
399 /* Swap Processes */
400 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
401 }
402
403 /* Return to old IRQL*/
404 KeReleaseDispatcherDatabaseLock(OldIrql);
405 }
406
407 /*
408 * @implemented
409 */
410 BOOLEAN
411 NTAPI
412 KeAddSystemServiceTable(PULONG_PTR Base,
413 PULONG Count OPTIONAL,
414 ULONG Limit,
415 PUCHAR Number,
416 ULONG Index)
417 {
418 /* Check if descriptor table entry is free */
419 if ((Index > SSDT_MAX_ENTRIES - 1) ||
420 (KeServiceDescriptorTable[Index].Base) ||
421 (KeServiceDescriptorTableShadow[Index].Base))
422 {
423 return FALSE;
424 }
425
426 /* Initialize the shadow service descriptor table */
427 KeServiceDescriptorTableShadow[Index].Base = Base;
428 KeServiceDescriptorTableShadow[Index].Limit = Limit;
429 KeServiceDescriptorTableShadow[Index].Number = Number;
430 KeServiceDescriptorTableShadow[Index].Count = Count;
431
432 return TRUE;
433 }
434
435 /*
436 * @implemented
437 */
438 BOOLEAN
439 NTAPI
440 KeRemoveSystemServiceTable(IN ULONG Index)
441 {
442 /* Make sure the Index is valid */
443 if (Index > SSDT_MAX_ENTRIES - 1) return FALSE;
444
445 /* Is there a Normal Descriptor Table? */
446 if (!KeServiceDescriptorTable[Index].Base)
447 {
448 /* Not with the index, is there a shadow at least? */
449 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE;
450 }
451
452 /* Now clear from the Shadow Table. */
453 KeServiceDescriptorTableShadow[Index].Base = NULL;
454 KeServiceDescriptorTableShadow[Index].Number = NULL;
455 KeServiceDescriptorTableShadow[Index].Limit = 0;
456 KeServiceDescriptorTableShadow[Index].Count = NULL;
457
458 /* Check if we should clean from the Master one too */
459 if (Index == 1)
460 {
461 KeServiceDescriptorTable[Index].Base = NULL;
462 KeServiceDescriptorTable[Index].Number = NULL;
463 KeServiceDescriptorTable[Index].Limit = 0;
464 KeServiceDescriptorTable[Index].Count = NULL;
465 }
466
467 return TRUE;
468 }
469 /* EOF */