3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/process.c
23 * PURPOSE: Microkernel process management
24 * PROGRAMMER: David Welch (welch@cwcom.net)
30 /* INCLUDES *****************************************************************/
34 #include <internal/debug.h>
36 /* FUNCTIONS *****************************************************************/
39 UpdatePageDirs(PKTHREAD Thread
, PKPROCESS Process
)
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
));
58 KeAttachProcess(PKPROCESS Process
)
61 PKTHREAD Thread
= KeGetCurrentThread();
63 DPRINT("KeAttachProcess: %x\n", Process
);
65 UpdatePageDirs(Thread
, Process
);
68 OldIrql
= KeAcquireDispatcherDatabaseLock();
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
);
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
);
81 KiAttachProcess(Thread
, Process
, OldIrql
, &Thread
->SavedApcState
);
87 KiAttachProcess(PKTHREAD Thread
, PKPROCESS Process
, KIRQL ApcLock
, PRKAPC_STATE SavedApcState
)
90 DPRINT("KiAttachProcess(Thread: %x, Process: %x, SavedApcState: %x\n", Thread
, Process
, SavedApcState
);
92 /* Increase Stack Count */
93 Process
->StackCount
++;
95 /* Swap the APC Environment */
96 KiMoveApcState(&Thread
->ApcState
, SavedApcState
);
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
;
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
;
113 /* Swap the Processes */
114 KiSwapProcess(Process
, SavedApcState
->Process
);
116 /* Return to old IRQL*/
117 KeReleaseDispatcherDatabaseLock(ApcLock
);
119 DPRINT("KiAttachProcess Completed Sucesfully\n");
124 KiSwapProcess(PKPROCESS NewProcess
, PKPROCESS OldProcess
)
126 //PKPCR Pcr = KeGetCurrentKpcr();
128 /* Do they have an LDT? */
129 if ((NewProcess
->LdtDescriptor
) || (OldProcess
->LdtDescriptor
)) {
130 /* FIXME : SWitch GDT/IDT */
132 DPRINT("Switching CR3 to: %x\n", NewProcess
->DirectoryTableBase
.u
.LowPart
);
133 Ke386SetPageTableDirectory(NewProcess
->DirectoryTableBase
.u
.LowPart
);
135 /* FIXME: Set IopmOffset in TSS */
147 return KeGetCurrentThread()->ApcStateIndex
;
155 KeStackAttachProcess (
156 IN PKPROCESS Process
,
157 OUT PRKAPC_STATE ApcState
161 PKTHREAD Thread
= KeGetCurrentThread();
163 UpdatePageDirs(Thread
, Process
);
165 OldIrql
= KeAcquireDispatcherDatabaseLock();
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
);
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 */
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
);
181 KiAttachProcess(Thread
, Process
, OldIrql
, &Thread
->SavedApcState
);
182 ApcState
->Process
= NULL
;
191 KeDetachProcess (VOID
)
196 DPRINT("KeDetachProcess()\n");
198 /* Get Current Thread and Lock */
199 Thread
= KeGetCurrentThread();
200 OldIrql
= KeAcquireDispatcherDatabaseLock();
202 /* Check if it's attached */
203 DPRINT("Current ApcStateIndex: %x\n", Thread
->ApcStateIndex
);
205 if (Thread
->ApcStateIndex
== OriginalApcEnvironment
) {
206 DPRINT1("Invalid detach (thread was not attached)\n");
207 KEBUGCHECK(INVALID_PROCESS_DETACH_ATTEMPT
);
210 /* Decrease Stack Count */
211 Thread
->ApcState
.Process
->StackCount
--;
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
;
221 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
223 /* Unlock Dispatcher */
224 KeReleaseDispatcherDatabaseLock(OldIrql
);
232 KeUnstackDetachProcess (
233 IN PRKAPC_STATE ApcState
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;
242 Thread
= KeGetCurrentThread();
243 OldIrql
= KeAcquireDispatcherDatabaseLock();
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
);
251 /* Restore the Old APC State if a Process was present */
252 if (ApcState
->Process
) {
253 RtlMoveMemory(ApcState
, &Thread
->ApcState
, sizeof(KAPC_STATE
));
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
;
263 /* Restore the APC State */
264 KiMoveApcState(&Thread
->SavedApcState
, &Thread
->ApcState
);
267 KiSwapProcess(Thread
->ApcState
.Process
, Thread
->ApcState
.Process
);
269 /* Return to old IRQL*/
270 KeReleaseDispatcherDatabaseLock(OldIrql
);
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
280 KeAddSystemServiceTable (
282 PULONG ServiceCounterTable
,
283 ULONG NumberOfServices
,
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
))
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
;
308 KeRemoveSystemServiceTable(