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
10 /* INCLUDES *****************************************************************/
13 #include <internal/napi.h>
15 #include <internal/debug.h>
17 /* GLOBALS *****************************************************************/
19 KSERVICE_TABLE_DESCRIPTOR
21 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
] =
32 { MainSSDT
, NULL
, NUMBER_OF_SYSCALLS
, MainSSPT
},
33 { NULL
, NULL
, 0, NULL
},
34 { NULL
, NULL
, 0, NULL
},
35 { NULL
, NULL
, 0, NULL
}
38 /* FUNCTIONS *****************************************************************/
42 KeGetCurrentProcess(VOID
)
44 return(&(PsGetCurrentProcess()->Pcb
));
50 UpdatePageDirs(IN PKTHREAD Thread
,
54 * The stack and the thread structure of the current process may be
55 * located in a page which is not present in the page directory of
56 * the process we're attaching to. That would lead to a page fault
57 * when this function returns. However, since the processor can't
58 * call the page fault handler 'cause it can't push EIP on the stack,
59 * this will show up as a stack fault which will crash the entire system.
60 * To prevent this, make sure the page directory of the process we're
61 * attaching to is up-to-date.
63 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
64 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
69 KiAttachProcess(PKTHREAD Thread
,
72 PRKAPC_STATE SavedApcState
)
74 ASSERT(Process
!= Thread
->ApcState
.Process
);
75 DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n",
76 Thread
, Process
, SavedApcState
);
78 /* Increase Stack Count */
79 Process
->StackCount
++;
81 /* Swap the APC Environment */
82 KiMoveApcState(&Thread
->ApcState
, SavedApcState
);
84 /* Reinitialize Apc State */
85 InitializeListHead(&Thread
->ApcState
.ApcListHead
[KernelMode
]);
86 InitializeListHead(&Thread
->ApcState
.ApcListHead
[UserMode
]);
87 Thread
->ApcState
.Process
= Process
;
88 Thread
->ApcState
.KernelApcInProgress
= FALSE
;
89 Thread
->ApcState
.KernelApcPending
= FALSE
;
90 Thread
->ApcState
.UserApcPending
= FALSE
;
92 /* Update Environment Pointers if needed*/
93 if (SavedApcState
== &Thread
->SavedApcState
)
95 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->SavedApcState
;
96 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->ApcState
;
97 Thread
->ApcStateIndex
= AttachedApcEnvironment
;
100 /* Check if the process is paged in */
101 if (Process
->State
== ProcessInMemory
)
103 /* FIXME: Scan the Ready Thread List once new scheduler is in */
105 /* Swap the Processes */
106 KiSwapProcess(Process
, SavedApcState
->Process
);
108 /* Return to old IRQL*/
109 KeReleaseDispatcherDatabaseLock(OldIrql
);
113 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n");
120 KeInitializeProcess(PKPROCESS Process
,
123 LARGE_INTEGER DirectoryTableBase
)
125 DPRINT("KeInitializeProcess. Process: %x, DirectoryTableBase: %x\n",
126 Process
, DirectoryTableBase
);
128 /* Initialize the Dispatcher Header */
129 KeInitializeDispatcherHeader(&Process
->Header
,
134 /* Initialize Scheduler Data, Disable Alignment Faults and Set the PDE */
135 Process
->Affinity
= Affinity
;
136 Process
->BasePriority
= Priority
;
137 Process
->QuantumReset
= 6;
138 Process
->DirectoryTableBase
= DirectoryTableBase
;
139 Process
->AutoAlignment
= TRUE
;
140 Process
->IopmOffset
= 0xFFFF;
141 Process
->State
= ProcessInMemory
;
143 /* Initialize the Thread List */
144 InitializeListHead(&Process
->ThreadListHead
);
145 KeInitializeSpinLock(&Process
->ProcessLock
);
146 DPRINT("The Process has now been initalized with the Kernel\n");
151 KeSetProcess(PKPROCESS Process
,
157 /* Lock Dispatcher */
158 OldIrql
= KeAcquireDispatcherDatabaseLock();
161 OldState
= Process
->Header
.SignalState
;
163 /* Signal the Process */
164 Process
->Header
.SignalState
= TRUE
;
165 if ((OldState
== 0) && IsListEmpty(&Process
->Header
.WaitListHead
) != TRUE
)
168 KiWaitTest((PVOID
)Process
, Increment
);
171 /* Release Dispatcher Database */
172 KeReleaseDispatcherDatabaseLock(OldIrql
);
174 /* Return the previous State */
180 KiSwapProcess(PKPROCESS NewProcess
,
181 PKPROCESS OldProcess
)
183 DPRINT("Switching CR3 to: %x\n", NewProcess
->DirectoryTableBase
.u
.LowPart
);
184 Ke386SetPageTableDirectory(NewProcess
->DirectoryTableBase
.u
.LowPart
);
192 KeAttachProcess(PKPROCESS Process
)
196 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
197 DPRINT("KeAttachProcess: %x\n", Process
);
199 /* Make sure that we are in the right page directory */
200 Thread
= KeGetCurrentThread();
201 UpdatePageDirs(Thread
, Process
);
203 /* Lock Dispatcher */
204 OldIrql
= KeAcquireDispatcherDatabaseLock();
206 /* Check if we're already in that process */
207 if (Thread
->ApcState
.Process
== Process
)
209 /* Unlock the dispatcher, nothing to do */
210 KeReleaseDispatcherDatabaseLock(OldIrql
);
212 else if ((Thread
->ApcStateIndex
!= OriginalApcEnvironment
) ||
213 (KeIsExecutingDpc()))
215 /* Executing a DPC or already attached, crash! */
216 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
218 (ULONG_PTR
)Thread
->ApcState
.Process
,
219 Thread
->ApcStateIndex
,
224 /* Legit attach attempt: do it! */
225 KiAttachProcess(Thread
, Process
, OldIrql
, &Thread
->SavedApcState
);
234 KeDetachProcess (VOID
)
238 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
239 DPRINT("KeDetachProcess()\n");
241 /* Get Current Thread and lock the dispatcher */
242 Thread
= KeGetCurrentThread();
243 OldIrql
= KeAcquireDispatcherDatabaseLock();
245 /* Check if it's attached */
246 if (Thread
->ApcStateIndex
!= OriginalApcEnvironment
)
248 /* It is, decrease Stack Count */
249 if(!(--Thread
->ApcState
.Process
->StackCount
))
251 /* FIXME: Swap the process out */
254 /* Restore the APC State */
255 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
256 Thread
->SavedApcState
.Process
= NULL
;
257 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
258 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
259 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
261 /* Check if we have pending APCs */
262 if (IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
]))
264 /* What do you know, we do! Request them to be delivered */
265 Thread
->ApcState
.KernelApcPending
= TRUE
;
266 HalRequestSoftwareInterrupt(APC_LEVEL
);
270 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
273 /* Unlock Dispatcher */
274 KeReleaseDispatcherDatabaseLock(OldIrql
);
282 KeIsAttachedProcess(VOID
)
284 /* Return the APC State */
285 return KeGetCurrentThread()->ApcStateIndex
;
293 KeStackAttachProcess(IN PKPROCESS Process
,
294 OUT PRKAPC_STATE ApcState
)
298 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
300 /* Make sure that we are in the right page directory */
301 Thread
= KeGetCurrentThread();
302 UpdatePageDirs(Thread
, Process
);
304 /* Acquire the dispatcher lock */
305 OldIrql
= KeAcquireDispatcherDatabaseLock();
307 /* Crash system if DPC is being executed! */
308 if (KeIsExecutingDpc())
310 /* Executing a DPC, crash! */
311 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
313 (ULONG_PTR
)Thread
->ApcState
.Process
,
314 Thread
->ApcStateIndex
,
318 /* Check if we are already in the target process */
319 if (Thread
->ApcState
.Process
== Process
)
321 /* Unlock the dispatcher database */
322 KeReleaseDispatcherDatabaseLock(OldIrql
);
324 /* Set magic value so we don't crash later when detaching */
325 ApcState
->Process
= (PKPROCESS
)1;
329 /* Check if the Current Thread is already attached */
330 if (Thread
->ApcStateIndex
!= OriginalApcEnvironment
)
332 /* We're already attached, so save the APC State into what we got */
333 KiAttachProcess(Thread
, Process
, OldIrql
, ApcState
);
337 /* We're not attached, so save the APC State into SavedApcState */
338 KiAttachProcess(Thread
, Process
, OldIrql
, &Thread
->SavedApcState
);
339 ApcState
->Process
= NULL
;
349 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState
)
353 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
355 /* Get the current thread and acquire the dispatcher lock */
356 Thread
= KeGetCurrentThread();
357 OldIrql
= KeAcquireDispatcherDatabaseLock();
359 /* Check for magic value meaning we were already in the same process */
360 if (ApcState
->Process
!= (PKPROCESS
)1)
363 * Check if the process isn't attacked, or has a Kernel APC in progress
364 * or has pending APC of any kind.
366 if ((Thread
->ApcStateIndex
== OriginalApcEnvironment
) ||
367 (Thread
->ApcState
.KernelApcInProgress
) ||
368 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
])) ||
369 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
371 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT
);
374 /* Decrease Stack Count */
375 if(!(--Thread
->ApcState
.Process
->StackCount
))
377 /* FIXME: Swap the process out */
380 if (ApcState
->Process
!= NULL
)
382 /* Restore the APC State */
383 KiMoveApcState(ApcState
, &Thread
->ApcState
);
387 /* The ApcState parameter is useless, so use the saved data and reset it */
388 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
389 Thread
->SavedApcState
.Process
= NULL
;
390 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
391 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
392 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
395 /* Check if we have pending APCs */
396 if (IsListEmpty(&Thread
->ApcState
.ApcListHead
[KernelMode
]))
398 /* What do you know, we do! Request them to be delivered */
399 Thread
->ApcState
.KernelApcPending
= TRUE
;
400 HalRequestSoftwareInterrupt(APC_LEVEL
);
404 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
407 /* Return to old IRQL*/
408 KeReleaseDispatcherDatabaseLock(OldIrql
);
416 KeAddSystemServiceTable(PULONG_PTR Base
,
417 PULONG Count OPTIONAL
,
422 /* Check if descriptor table entry is free */
423 if ((Index
> SSDT_MAX_ENTRIES
- 1) ||
424 (KeServiceDescriptorTable
[Index
].Base
) ||
425 (KeServiceDescriptorTableShadow
[Index
].Base
))
430 /* Initialize the shadow service descriptor table */
431 KeServiceDescriptorTableShadow
[Index
].Base
= Base
;
432 KeServiceDescriptorTableShadow
[Index
].Limit
= Limit
;
433 KeServiceDescriptorTableShadow
[Index
].Number
= Number
;
434 KeServiceDescriptorTableShadow
[Index
].Count
= Count
;
444 KeRemoveSystemServiceTable(IN ULONG Index
)
446 /* Make sure the Index is valid */
447 if (Index
> SSDT_MAX_ENTRIES
- 1) return FALSE
;
449 /* Is there a Normal Descriptor Table? */
450 if (!KeServiceDescriptorTable
[Index
].Base
)
452 /* Not with the index, is there a shadow at least? */
453 if (!KeServiceDescriptorTableShadow
[Index
].Base
) return FALSE
;
456 /* Now clear from the Shadow Table. */
457 KeServiceDescriptorTableShadow
[Index
].Base
= NULL
;
458 KeServiceDescriptorTableShadow
[Index
].Number
= NULL
;
459 KeServiceDescriptorTableShadow
[Index
].Limit
= 0;
460 KeServiceDescriptorTableShadow
[Index
].Count
= NULL
;
462 /* Check if we should clean from the Master one too */
465 KeServiceDescriptorTable
[Index
].Base
= NULL
;
466 KeServiceDescriptorTable
[Index
].Number
= NULL
;
467 KeServiceDescriptorTable
[Index
].Limit
= 0;
468 KeServiceDescriptorTable
[Index
].Count
= NULL
;