SYSENTER support, INT2E Optimization, new Syscall Table/Stub generator and svn:ignore...
[reactos.git] / reactos / ntoskrnl / ke / process.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/process.c
23 * PURPOSE: Microkernel process management
24 * PROGRAMMER: David Welch (welch@cwcom.net)
25 * PORTABILITY: No.
26 * UPDATE HISTORY:
27 * Created 22/05/98
28 */
29
30 /* INCLUDES *****************************************************************/
31
32 #include <ntoskrnl.h>
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 /* FUNCTIONS *****************************************************************/
37
38 static inline void
39 UpdatePageDirs(PKTHREAD Thread, PKPROCESS Process)
40 {
41 /* The stack and the thread structure of the current process may be
42 located in a page which is not present in the page directory of
43 the process we're attaching to. That would lead to a page fault
44 when this function returns. However, since the processor can't
45 call the page fault handler 'cause it can't push EIP on the stack,
46 this will show up as a stack fault which will crash the entire system.
47 To prevent this, make sure the page directory of the process we're
48 attaching to is up-to-date. */
49 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread->StackLimit, MM_STACK_SIZE);
50 MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
51 }
52
53 /*
54 * @implemented
55 */
56 VOID
57 STDCALL
58 KeAttachProcess(PKPROCESS Process)
59 {
60 KIRQL OldIrql;
61 PKTHREAD Thread = KeGetCurrentThread();
62
63 DPRINT("KeAttachProcess: %x\n", Process);
64
65 UpdatePageDirs(Thread, Process);
66
67 /* Lock Dispatcher */
68 OldIrql = KeAcquireDispatcherDatabaseLock();
69
70 /* Crash system if DPC is being executed! */
71 if (KeIsExecutingDpc()) {
72 DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
73 KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT);
74 }
75
76 /* Check if the Target Process is already attached */
77 if (Thread->ApcState.Process == Process || Thread->ApcStateIndex != OriginalApcEnvironment) {
78 DPRINT("Process already Attached. Exitting\n");
79 KeReleaseDispatcherDatabaseLock(OldIrql);
80 } else {
81 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
82 }
83 }
84
85 VOID
86 STDCALL
87 KiAttachProcess(PKTHREAD Thread, PKPROCESS Process, KIRQL ApcLock, PRKAPC_STATE SavedApcState)
88 {
89
90 DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n", Thread, Process, SavedApcState);
91
92 /* Increase Stack Count */
93 Process->StackCount++;
94
95 /* Swap the APC Environment */
96 KiMoveApcState(&Thread->ApcState, SavedApcState);
97
98 /* Reinitialize Apc State */
99 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
100 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
101 Thread->ApcState.Process = Process;
102 Thread->ApcState.KernelApcInProgress = FALSE;
103 Thread->ApcState.KernelApcPending = FALSE;
104 Thread->ApcState.UserApcPending = FALSE;
105
106 /* Update Environment Pointers if needed*/
107 if (SavedApcState == &Thread->SavedApcState) {
108 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->SavedApcState;
109 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState;
110 Thread->ApcStateIndex = AttachedApcEnvironment;
111 }
112
113 /* Swap the Processes */
114 KiSwapProcess(Process, SavedApcState->Process);
115
116 /* Return to old IRQL*/
117 KeReleaseDispatcherDatabaseLock(ApcLock);
118
119 DPRINT("KiAttachProcess Completed Sucesfully\n");
120 }
121
122 VOID
123 STDCALL
124 KiSwapProcess(PKPROCESS NewProcess, PKPROCESS OldProcess)
125 {
126 //PKPCR Pcr = KeGetCurrentKpcr();
127
128 /* Do they have an LDT? */
129 if ((NewProcess->LdtDescriptor) || (OldProcess->LdtDescriptor)) {
130 /* FIXME : SWitch GDT/IDT */
131 }
132 DPRINT("Switching CR3 to: %x\n", NewProcess->DirectoryTableBase.u.LowPart);
133 Ke386SetPageTableDirectory(NewProcess->DirectoryTableBase.u.LowPart);
134
135 /* FIXME: Set IopmOffset in TSS */
136 }
137
138 /*
139 * @implemented
140 */
141 BOOLEAN
142 STDCALL
143 KeIsAttachedProcess(
144 VOID
145 )
146 {
147 return KeGetCurrentThread()->ApcStateIndex;
148 }
149
150 /*
151 * @implemented
152 */
153 VOID
154 STDCALL
155 KeStackAttachProcess (
156 IN PKPROCESS Process,
157 OUT PRKAPC_STATE ApcState
158 )
159 {
160 KIRQL OldIrql;
161 PKTHREAD Thread = KeGetCurrentThread();
162
163 UpdatePageDirs(Thread, Process);
164
165 OldIrql = KeAcquireDispatcherDatabaseLock();
166
167 /* Crash system if DPC is being executed! */
168 if (KeIsExecutingDpc()) {
169 DPRINT1("Invalid attach (Thread is executing a DPC!)\n");
170 KEBUGCHECK(INVALID_PROCESS_ATTACH_ATTEMPT);
171 }
172
173 /* Check if the Target Process is already attached */
174 if (Thread->ApcState.Process == Process) {
175 ApcState->Process = (PKPROCESS)1; /* Meaning already attached to the same Process */
176 } else {
177 /* Check if the Current Thread is already attached and call the Internal Function*/
178 if (Thread->ApcStateIndex != OriginalApcEnvironment) {
179 KiAttachProcess(Thread, Process, OldIrql, ApcState);
180 } else {
181 KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
182 ApcState->Process = NULL;
183 }
184 }
185 }
186
187 /*
188 * @implemented
189 */
190 VOID STDCALL
191 KeDetachProcess (VOID)
192 {
193 PKTHREAD Thread;
194 KIRQL OldIrql;
195
196 DPRINT("KeDetachProcess()\n");
197
198 /* Get Current Thread and Lock */
199 Thread = KeGetCurrentThread();
200 OldIrql = KeAcquireDispatcherDatabaseLock();
201
202 /* Check if it's attached */
203 DPRINT("Current ApcStateIndex: %x\n", Thread->ApcStateIndex);
204
205 if (Thread->ApcStateIndex == OriginalApcEnvironment) {
206 DPRINT1("Invalid detach (thread was not attached)\n");
207 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
208 }
209
210 /* Decrease Stack Count */
211 Thread->ApcState.Process->StackCount--;
212
213 /* Restore the APC State */
214 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
215 Thread->SavedApcState.Process = NULL;
216 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
217 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
218 Thread->ApcStateIndex = OriginalApcEnvironment;
219
220 /* Swap Processes */
221 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
222
223 /* Unlock Dispatcher */
224 KeReleaseDispatcherDatabaseLock(OldIrql);
225 }
226
227 /*
228 * @implemented
229 */
230 VOID
231 STDCALL
232 KeUnstackDetachProcess (
233 IN PRKAPC_STATE ApcState
234 )
235 {
236 KIRQL OldIrql;
237 PKTHREAD Thread;
238
239 /* If the special "We tried to attach to the process already being attached to" flag is there, don't do anything */
240 if (ApcState->Process == (PKPROCESS)1) return;
241
242 Thread = KeGetCurrentThread();
243 OldIrql = KeAcquireDispatcherDatabaseLock();
244
245 /* Sorry Buddy, can't help you if you've got APCs or just aren't attached */
246 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || (Thread->ApcState.KernelApcInProgress)) {
247 DPRINT1("Invalid detach (Thread not Attached, or Kernel APC in Progress!)\n");
248 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT);
249 }
250
251 /* Restore the Old APC State if a Process was present */
252 if (ApcState->Process) {
253 RtlMoveMemory(ApcState, &Thread->ApcState, sizeof(KAPC_STATE));
254 } else {
255 /* The ApcState parameter is useless, so use the saved data and reset it */
256 RtlMoveMemory(&Thread->SavedApcState, &Thread->ApcState, sizeof(KAPC_STATE));
257 Thread->SavedApcState.Process = NULL;
258 Thread->ApcStateIndex = OriginalApcEnvironment;
259 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
260 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
261 }
262
263 /* Restore the APC State */
264 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
265
266 /* Swap Processes */
267 KiSwapProcess(Thread->ApcState.Process, Thread->ApcState.Process);
268
269 /* Return to old IRQL*/
270 KeReleaseDispatcherDatabaseLock(OldIrql);
271 }
272
273 // This function should be used by win32k.sys to add its own user32/gdi32 services
274 // TableIndex is 0 based
275 // ServiceCountTable its not used at the moment
276 /*
277 * @implemented
278 */
279 BOOLEAN STDCALL
280 KeAddSystemServiceTable (
281 PSSDT SSDT,
282 PULONG ServiceCounterTable,
283 ULONG NumberOfServices,
284 PSSPT SSPT,
285 ULONG TableIndex
286 )
287 {
288 /* check if descriptor table entry is free */
289 if ((TableIndex > SSDT_MAX_ENTRIES - 1) ||
290 (KeServiceDescriptorTable[TableIndex].SSDT != NULL) ||
291 (KeServiceDescriptorTableShadow[TableIndex].SSDT != NULL))
292 return FALSE;
293
294 /* initialize the shadow service descriptor table */
295 KeServiceDescriptorTableShadow[TableIndex].SSDT = SSDT;
296 KeServiceDescriptorTableShadow[TableIndex].SSPT = SSPT;
297 KeServiceDescriptorTableShadow[TableIndex].NumberOfServices = NumberOfServices;
298 KeServiceDescriptorTableShadow[TableIndex].ServiceCounterTable = ServiceCounterTable;
299
300 return TRUE;
301 }
302
303 /*
304 * @unimplemented
305 */
306 BOOLEAN
307 STDCALL
308 KeRemoveSystemServiceTable(
309 IN PUCHAR Number
310 )
311 {
312 UNIMPLEMENTED;
313 return FALSE;
314 }
315 /* EOF */