3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/win32.c
6 * PURPOSE: win32k support
8 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
11 /* INCLUDES ****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ******************************************************************/
19 static PW32_PROCESS_CALLBACK PspWin32ProcessCallback
= NULL
;
20 static PW32_THREAD_CALLBACK PspWin32ThreadCallback
= NULL
;
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
;
29 #ifndef ALEX_CB_REWRITE
30 typedef struct _NTW32CALL_SAVED_STATE
32 ULONG_PTR SavedStackLimit
;
34 PVOID SavedInitialStack
;
36 PULONG CallerResultLength
;
37 PNTSTATUS CallbackStatus
;
38 PKTRAP_FRAME SavedTrapFrame
;
39 PVOID SavedCallbackStack
;
40 PVOID SavedExceptionStack
;
41 } NTW32CALL_SAVED_STATE
, *PNTW32CALL_SAVED_STATE
;
51 /* FUNCTIONS ***************************************************************/
58 PsEstablishWin32Callouts(PW32_CALLOUT_DATA CalloutData
)
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
;
72 PsConvertToGuiThread(VOID
)
74 PVOID NewStack
, OldStack
;
75 PETHREAD Thread
= PsGetCurrentThread();
76 PEPROCESS Process
= PsGetCurrentProcess();
80 /* Validate the previous mode */
81 if (KeGetPreviousMode() == KernelMode
)
83 DPRINT1("Danger: win32k call being made in kernel-mode?!\n");
84 return STATUS_INVALID_PARAMETER
;
87 /* Make sure win32k is here */
88 if (!PspWin32ProcessCallback
)
90 DPRINT1("Danger: Win32K call attempted but Win32k not ready!\n");
91 return STATUS_ACCESS_DENIED
;
94 /* Make sure it's not already win32 */
95 if (Thread
->Tcb
.ServiceTable
!= KeServiceDescriptorTable
)
97 DPRINT1("Danger: Thread is already a win32 thread. Limit bypassed?\n");
98 return STATUS_ALREADY_WIN32
;
101 /* Check if we don't already have a kernel-mode stack */
102 if (!Thread
->Tcb
.LargeStack
)
104 /* We don't create one */
105 NewStack
= MmCreateKernelStack(TRUE
);
108 /* Panic in user-mode */
109 NtCurrentTeb()->LastErrorValue
= ERROR_NOT_ENOUGH_MEMORY
;
110 return STATUS_NO_MEMORY
;
113 /* We're about to switch stacks. Enter a critical region */
114 KeEnterCriticalRegion();
117 OldStack
= KeSwitchKernelStack((PVOID
)((ULONG_PTR
)NewStack
+ 0x3000),
120 /* Leave the critical region */
121 KeLeaveCriticalRegion();
123 /* Delete the old stack */
124 //MmDeleteKernelStack(OldStack, FALSE);
127 /* This check is bizare. Check out win32k later */
128 if (!Process
->Win32Process
)
130 /* Now tell win32k about us */
131 Status
= PspWin32ProcessCallback(Process
, TRUE
);
132 if (!NT_SUCCESS(Status
))
134 DPRINT1("Danger: Win32k wasn't happy about us!\n");
139 /* Set the new service table */
140 Thread
->Tcb
.ServiceTable
= KeServiceDescriptorTableShadow
;
141 ASSERT(Thread
->Tcb
.Win32Thread
== 0);
143 /* Tell Win32k about our thread */
144 Status
= PspWin32ThreadCallback(Thread
, TRUE
);
145 if (!NT_SUCCESS(Status
))
147 /* Revert our table */
148 DPRINT1("Danger: Win32k wasn't happy about us!\n");
149 Thread
->Tcb
.ServiceTable
= KeServiceDescriptorTable
;
158 PsTerminateWin32Process (PEPROCESS Process
)
160 if (Process
->Win32Process
== NULL
)
163 if (PspWin32ProcessCallback
!= NULL
)
165 PspWin32ProcessCallback (Process
, FALSE
);
168 /* don't delete the W32PROCESS structure at this point, wait until the
169 EPROCESS structure is being freed */
175 PsTerminateWin32Thread (PETHREAD Thread
)
177 if (Thread
->Tcb
.Win32Thread
!= NULL
)
179 if (PspWin32ThreadCallback
!= NULL
)
181 PspWin32ThreadCallback (Thread
, FALSE
);
184 /* don't delete the W32THREAD structure at this point, wait until the
185 ETHREAD structure is being freed */
191 NtW32Call(IN ULONG RoutineIndex
,
193 IN ULONG ArgumentLength
,
194 OUT PVOID
* Result OPTIONAL
,
195 OUT PULONG ResultLength OPTIONAL
)
197 NTSTATUS CallbackStatus
;
199 DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
200 RoutineIndex
, Argument
, ArgumentLength
);
204 /* Call kernel function */
205 CallbackStatus
= KeUserModeCallback(RoutineIndex
,
211 /* Return the result */
212 return(CallbackStatus
);
215 #ifndef ALEX_CB_REWRITE
217 NtCallbackReturn (PVOID Result
,
223 PNTSTATUS CallbackStatus
;
224 PULONG CallerResultLength
;
228 ULONG_PTR StackLimit
;
230 PNTW32CALL_SAVED_STATE State
;
231 PKTRAP_FRAME SavedTrapFrame
;
232 PVOID SavedCallbackStack
;
233 PVOID SavedExceptionStack
;
237 Thread
= PsGetCurrentThread();
238 if (Thread
->Tcb
.CallbackStack
== NULL
)
240 return(STATUS_NO_CALLBACK_ACTIVE
);
243 OldStack
= (PULONG
)Thread
->Tcb
.CallbackStack
;
246 * Get the values that NtW32Call left on the inactive stack for us.
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
;
260 * Copy the callback status and the callback result to NtW32Call
262 *CallbackStatus
= Status
;
263 if (CallerResult
!= NULL
&& CallerResultLength
!= NULL
)
267 *CallerResultLength
= 0;
271 *CallerResultLength
= min(ResultLength
, *CallerResultLength
);
272 RtlCopyMemory(*CallerResult
, Result
, *CallerResultLength
);
277 * Restore the old stack.
279 KeRaiseIrql(HIGH_LEVEL
, &oldIrql
);
280 if ((Thread
->Tcb
.NpxState
& NPX_STATE_VALID
) &&
281 &Thread
->Tcb
!= KeGetCurrentPrcb()->NpxThread
)
283 RtlCopyMemory((char*)InitialStack
- sizeof(FX_SAVE_AREA
),
284 (char*)Thread
->Tcb
.InitialStack
- sizeof(FX_SAVE_AREA
),
285 sizeof(FX_SAVE_AREA
));
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));
295 /* Should never return. */
297 return(STATUS_UNSUCCESSFUL
);