- Fix MmCreateKernelStack to actually take into account the GuiStack parameter.
[reactos.git] / reactos / ntoskrnl / ps / win32.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/win32.c
6 * PURPOSE: win32k support
7 *
8 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 static PW32_PROCESS_CALLBACK PspWin32ProcessCallback = NULL;
20 static PW32_THREAD_CALLBACK PspWin32ThreadCallback = NULL;
21
22 extern OB_OPEN_METHOD ExpWindowStationObjectOpen;
23 extern OB_PARSE_METHOD ExpWindowStationObjectParse;
24 extern OB_DELETE_METHOD ExpWindowStationObjectDelete;
25 extern OB_FIND_METHOD ExpWindowStationObjectFind;
26 extern OB_CREATE_METHOD ExpDesktopObjectCreate;
27 extern OB_DELETE_METHOD ExpDesktopObjectDelete;
28
29 #ifndef ALEX_CB_REWRITE
30 typedef struct _NTW32CALL_SAVED_STATE
31 {
32 ULONG_PTR SavedStackLimit;
33 PVOID SavedStackBase;
34 PVOID SavedInitialStack;
35 PVOID CallerResult;
36 PULONG CallerResultLength;
37 PNTSTATUS CallbackStatus;
38 PKTRAP_FRAME SavedTrapFrame;
39 PVOID SavedCallbackStack;
40 PVOID SavedExceptionStack;
41 } NTW32CALL_SAVED_STATE, *PNTW32CALL_SAVED_STATE;
42 #endif
43
44 PVOID
45 STDCALL
46 KeSwitchKernelStack(
47 IN PVOID StackBase,
48 IN PVOID StackLimit
49 );
50
51 /* FUNCTIONS ***************************************************************/
52
53 /*
54 * @implemented
55 */
56 VOID
57 STDCALL
58 PsEstablishWin32Callouts(PW32_CALLOUT_DATA CalloutData)
59 {
60 PspWin32ProcessCallback = CalloutData->W32ProcessCallout;
61 PspWin32ThreadCallback = CalloutData->W32ThreadCallout;
62 ExpWindowStationObjectOpen = CalloutData->WinStaCreate;
63 ExpWindowStationObjectParse = CalloutData->WinStaParse;
64 ExpWindowStationObjectDelete = CalloutData->WinStaDelete;
65 ExpWindowStationObjectFind = CalloutData->WinStaFind;
66 ExpDesktopObjectCreate = CalloutData->DesktopCreate;
67 ExpDesktopObjectDelete = CalloutData->DesktopDelete;
68 }
69
70 NTSTATUS
71 NTAPI
72 PsConvertToGuiThread(VOID)
73 {
74 PVOID NewStack, OldStack;
75 PETHREAD Thread = PsGetCurrentThread();
76 PEPROCESS Process = PsGetCurrentProcess();
77 NTSTATUS Status;
78 PAGED_CODE();
79
80 /* Validate the previous mode */
81 if (KeGetPreviousMode() == KernelMode)
82 {
83 DPRINT1("Danger: win32k call being made in kernel-mode?!\n");
84 return STATUS_INVALID_PARAMETER;
85 }
86
87 /* Make sure win32k is here */
88 if (!PspWin32ProcessCallback)
89 {
90 DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n");
91 return STATUS_ACCESS_DENIED;
92 }
93
94 /* Make sure it's not already win32 */
95 if (Thread->Tcb.ServiceTable != KeServiceDescriptorTable)
96 {
97 DPRINT1("Danger: Thread is already a win32 thread. Limit bypassed?\n");
98 return STATUS_ALREADY_WIN32;
99 }
100
101 /* Check if we don't already have a kernel-mode stack */
102 if (!Thread->Tcb.LargeStack)
103 {
104 /* We don't create one */
105 NewStack = MmCreateKernelStack(TRUE);
106 if (!NewStack)
107 {
108 /* Panic in user-mode */
109 NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
110 return STATUS_NO_MEMORY;
111 }
112
113 /* We're about to switch stacks. Enter a critical region */
114 KeEnterCriticalRegion();
115
116 /* Switch stacks */
117 OldStack = KeSwitchKernelStack((PVOID)((ULONG_PTR)NewStack + 0x3000),
118 NewStack);
119
120 /* Leave the critical region */
121 KeLeaveCriticalRegion();
122
123 /* Delete the old stack */
124 //MmDeleteKernelStack(OldStack, FALSE);
125 }
126
127 /* This check is bizare. Check out win32k later */
128 if (!Process->Win32Process)
129 {
130 /* Now tell win32k about us */
131 Status = PspWin32ProcessCallback(Process, TRUE);
132 if (!NT_SUCCESS(Status))
133 {
134 DPRINT1("Danger: Win32k wasn't happy about us!\n");
135 return Status;
136 }
137 }
138
139 /* Set the new service table */
140 Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
141 ASSERT(Thread->Tcb.Win32Thread == 0);
142
143 /* Tell Win32k about our thread */
144 Status = PspWin32ThreadCallback(Thread, TRUE);
145 if (!NT_SUCCESS(Status))
146 {
147 /* Revert our table */
148 DPRINT1("Danger: Win32k wasn't happy about us!\n");
149 Thread->Tcb.ServiceTable = KeServiceDescriptorTable;
150 }
151
152 /* Return status */
153 return Status;
154 }
155
156 VOID
157 NTAPI
158 PsTerminateWin32Process (PEPROCESS Process)
159 {
160 if (Process->Win32Process == NULL)
161 return;
162
163 if (PspWin32ProcessCallback != NULL)
164 {
165 PspWin32ProcessCallback (Process, FALSE);
166 }
167
168 /* don't delete the W32PROCESS structure at this point, wait until the
169 EPROCESS structure is being freed */
170 }
171
172
173 VOID
174 NTAPI
175 PsTerminateWin32Thread (PETHREAD Thread)
176 {
177 if (Thread->Tcb.Win32Thread != NULL)
178 {
179 if (PspWin32ThreadCallback != NULL)
180 {
181 PspWin32ThreadCallback (Thread, FALSE);
182 }
183
184 /* don't delete the W32THREAD structure at this point, wait until the
185 ETHREAD structure is being freed */
186 }
187 }
188
189 NTSTATUS
190 STDCALL
191 NtW32Call(IN ULONG RoutineIndex,
192 IN PVOID Argument,
193 IN ULONG ArgumentLength,
194 OUT PVOID* Result OPTIONAL,
195 OUT PULONG ResultLength OPTIONAL)
196 {
197 NTSTATUS CallbackStatus;
198
199 DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
200 RoutineIndex, Argument, ArgumentLength);
201
202 /* FIXME: SEH!!! */
203
204 /* Call kernel function */
205 CallbackStatus = KeUserModeCallback(RoutineIndex,
206 Argument,
207 ArgumentLength,
208 Result,
209 ResultLength);
210
211 /* Return the result */
212 return(CallbackStatus);
213 }
214
215 #ifndef ALEX_CB_REWRITE
216 NTSTATUS STDCALL
217 NtCallbackReturn (PVOID Result,
218 ULONG ResultLength,
219 NTSTATUS Status)
220 {
221 PULONG OldStack;
222 PETHREAD Thread;
223 PNTSTATUS CallbackStatus;
224 PULONG CallerResultLength;
225 PVOID* CallerResult;
226 PVOID InitialStack;
227 PVOID StackBase;
228 ULONG_PTR StackLimit;
229 KIRQL oldIrql;
230 PNTW32CALL_SAVED_STATE State;
231 PKTRAP_FRAME SavedTrapFrame;
232 PVOID SavedCallbackStack;
233 PVOID SavedExceptionStack;
234
235 PAGED_CODE();
236
237 Thread = PsGetCurrentThread();
238 if (Thread->Tcb.CallbackStack == NULL)
239 {
240 return(STATUS_NO_CALLBACK_ACTIVE);
241 }
242
243 OldStack = (PULONG)Thread->Tcb.CallbackStack;
244
245 /*
246 * Get the values that NtW32Call left on the inactive stack for us.
247 */
248 State = (PNTW32CALL_SAVED_STATE)OldStack[0];
249 CallbackStatus = State->CallbackStatus;
250 CallerResultLength = State->CallerResultLength;
251 CallerResult = State->CallerResult;
252 InitialStack = State->SavedInitialStack;
253 StackBase = State->SavedStackBase;
254 StackLimit = State->SavedStackLimit;
255 SavedTrapFrame = State->SavedTrapFrame;
256 SavedCallbackStack = State->SavedCallbackStack;
257 SavedExceptionStack = State->SavedExceptionStack;
258
259 /*
260 * Copy the callback status and the callback result to NtW32Call
261 */
262 *CallbackStatus = Status;
263 if (CallerResult != NULL && CallerResultLength != NULL)
264 {
265 if (Result == NULL)
266 {
267 *CallerResultLength = 0;
268 }
269 else
270 {
271 *CallerResultLength = min(ResultLength, *CallerResultLength);
272 RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
273 }
274 }
275
276 /*
277 * Restore the old stack.
278 */
279 KeRaiseIrql(HIGH_LEVEL, &oldIrql);
280 if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
281 &Thread->Tcb != KeGetCurrentPrcb()->NpxThread)
282 {
283 RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA),
284 (char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
285 sizeof(FX_SAVE_AREA));
286 }
287 Thread->Tcb.InitialStack = InitialStack;
288 Thread->Tcb.StackBase = StackBase;
289 Thread->Tcb.StackLimit = StackLimit;
290 Thread->Tcb.TrapFrame = SavedTrapFrame;
291 Thread->Tcb.CallbackStack = SavedCallbackStack;
292 KeGetCurrentKPCR()->TSS->Esp0 = (ULONG)SavedExceptionStack;
293 KeStackSwitchAndRet((PVOID)(OldStack + 1));
294
295 /* Should never return. */
296 KEBUGCHECK(0);
297 return(STATUS_UNSUCCESSFUL);
298 }
299 #endif
300 /* EOF */