add SEH to NtW32Call and directly use KeUserModeCallback in win32k instead
[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 ULONG_PTR NewStack;
75 PVOID OldStack;
76 PETHREAD Thread = PsGetCurrentThread();
77 PEPROCESS Process = PsGetCurrentProcess();
78 NTSTATUS Status;
79 PAGED_CODE();
80
81 /* Validate the previous mode */
82 if (KeGetPreviousMode() == KernelMode)
83 {
84 DPRINT1("Danger: win32k call being made in kernel-mode?!\n");
85 return STATUS_INVALID_PARAMETER;
86 }
87
88 /* Make sure win32k is here */
89 if (!PspWin32ProcessCallback)
90 {
91 DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n");
92 return STATUS_ACCESS_DENIED;
93 }
94
95 /* Make sure it's not already win32 */
96 if (Thread->Tcb.ServiceTable != KeServiceDescriptorTable)
97 {
98 DPRINT1("Danger: Thread is already a win32 thread. Limit bypassed?\n");
99 return STATUS_ALREADY_WIN32;
100 }
101
102 /* Check if we don't already have a kernel-mode stack */
103 if (!Thread->Tcb.LargeStack)
104 {
105 /* We don't create one */
106 NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE) + KERNEL_LARGE_STACK_SIZE;
107 if (!NewStack)
108 {
109 /* Panic in user-mode */
110 NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
111 return STATUS_NO_MEMORY;
112 }
113
114 /* We're about to switch stacks. Enter a critical region */
115 KeEnterCriticalRegion();
116
117 /* Switch stacks */
118 OldStack = KeSwitchKernelStack((PVOID)NewStack,
119 (PVOID)(NewStack - KERNEL_STACK_SIZE));
120
121 /* Leave the critical region */
122 KeLeaveCriticalRegion();
123
124 /* Delete the old stack */
125 MmDeleteKernelStack(OldStack, FALSE);
126 }
127
128 /* This check is bizare. Check out win32k later */
129 if (!Process->Win32Process)
130 {
131 /* Now tell win32k about us */
132 Status = PspWin32ProcessCallback(Process, TRUE);
133 if (!NT_SUCCESS(Status))
134 {
135 DPRINT1("Danger: Win32k wasn't happy about us!\n");
136 return Status;
137 }
138 }
139
140 /* Set the new service table */
141 Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
142 ASSERT(Thread->Tcb.Win32Thread == 0);
143
144 /* Tell Win32k about our thread */
145 Status = PspWin32ThreadCallback(Thread, TRUE);
146 if (!NT_SUCCESS(Status))
147 {
148 /* Revert our table */
149 DPRINT1("Danger: Win32k wasn't happy about us!\n");
150 Thread->Tcb.ServiceTable = KeServiceDescriptorTable;
151 }
152
153 /* Return status */
154 return Status;
155 }
156
157 VOID
158 NTAPI
159 PsTerminateWin32Process (PEPROCESS Process)
160 {
161 if (Process->Win32Process == NULL)
162 return;
163
164 if (PspWin32ProcessCallback != NULL)
165 {
166 PspWin32ProcessCallback (Process, FALSE);
167 }
168
169 /* don't delete the W32PROCESS structure at this point, wait until the
170 EPROCESS structure is being freed */
171 }
172
173
174 VOID
175 NTAPI
176 PsTerminateWin32Thread (PETHREAD Thread)
177 {
178 if (Thread->Tcb.Win32Thread != NULL)
179 {
180 if (PspWin32ThreadCallback != NULL)
181 {
182 PspWin32ThreadCallback (Thread, FALSE);
183 }
184
185 /* don't delete the W32THREAD structure at this point, wait until the
186 ETHREAD structure is being freed */
187 }
188 }
189
190 NTSTATUS
191 STDCALL
192 NtW32Call(IN ULONG RoutineIndex,
193 IN PVOID Argument,
194 IN ULONG ArgumentLength,
195 OUT PVOID* Result,
196 OUT PULONG ResultLength)
197 {
198 PVOID RetResult;
199 ULONG RetResultLength;
200 NTSTATUS Status = STATUS_SUCCESS;
201
202 DPRINT("NtW32Call(RoutineIndex %d, Argument %p, ArgumentLength %d)\n",
203 RoutineIndex, Argument, ArgumentLength);
204
205 /* must not be called as KernelMode! */
206 ASSERT(KeGetPreviousMode() != KernelMode);
207
208 _SEH_TRY
209 {
210 ProbeForWritePointer(Result);
211 ProbeForWriteUlong(ResultLength);
212 }
213 _SEH_HANDLE
214 {
215 Status = _SEH_GetExceptionCode();
216 }
217 _SEH_END;
218
219 if (NT_SUCCESS(Status))
220 {
221 /* Call kernel function */
222 Status = KeUserModeCallback(RoutineIndex,
223 Argument,
224 ArgumentLength,
225 &RetResult,
226 &RetResultLength);
227
228 if (NT_SUCCESS(Status))
229 {
230 _SEH_TRY
231 {
232 *Result = RetResult;
233 *ResultLength = RetResultLength;
234 }
235 _SEH_HANDLE
236 {
237 Status = _SEH_GetExceptionCode();
238 }
239 _SEH_END;
240 }
241 }
242
243 /* Return the result */
244 return Status;
245 }
246
247 /* EOF */