- Implemented InterlockedBitTestAndReset, InterlockedBitTestAndSet, InterlockedExchan...
[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 /* FUNCTIONS ***************************************************************/
45
46 /*
47 * @implemented
48 */
49 VOID
50 STDCALL
51 PsEstablishWin32Callouts(PW32_CALLOUT_DATA CalloutData)
52 {
53 PspWin32ProcessCallback = CalloutData->W32ProcessCallout;
54 PspWin32ThreadCallback = CalloutData->W32ThreadCallout;
55 ExpWindowStationObjectOpen = CalloutData->WinStaCreate;
56 ExpWindowStationObjectParse = CalloutData->WinStaParse;
57 ExpWindowStationObjectDelete = CalloutData->WinStaDelete;
58 ExpWindowStationObjectFind = CalloutData->WinStaFind;
59 ExpDesktopObjectCreate = CalloutData->DesktopCreate;
60 ExpDesktopObjectDelete = CalloutData->DesktopDelete;
61 }
62
63 NTSTATUS
64 NTAPI
65 PsInitWin32Thread (PETHREAD Thread)
66 {
67 PEPROCESS Process;
68 NTSTATUS Status = STATUS_SUCCESS;
69
70 Process = Thread->ThreadsProcess;
71
72 if (Process->Win32Process == NULL)
73 {
74 if (PspWin32ProcessCallback != NULL)
75 {
76 Status = PspWin32ProcessCallback(Process, TRUE);
77 }
78 }
79
80 if (Thread->Tcb.Win32Thread == NULL)
81 {
82 if (PspWin32ThreadCallback != NULL)
83 {
84 Status = PspWin32ThreadCallback(Thread, TRUE);
85 }
86 }
87
88 return Status;
89 }
90
91
92 VOID
93 NTAPI
94 PsTerminateWin32Process (PEPROCESS Process)
95 {
96 if (Process->Win32Process == NULL)
97 return;
98
99 if (PspWin32ProcessCallback != NULL)
100 {
101 PspWin32ProcessCallback (Process, FALSE);
102 }
103
104 /* don't delete the W32PROCESS structure at this point, wait until the
105 EPROCESS structure is being freed */
106 }
107
108
109 VOID
110 NTAPI
111 PsTerminateWin32Thread (PETHREAD Thread)
112 {
113 if (Thread->Tcb.Win32Thread != NULL)
114 {
115 if (PspWin32ThreadCallback != NULL)
116 {
117 PspWin32ThreadCallback (Thread, FALSE);
118 }
119
120 /* don't delete the W32THREAD structure at this point, wait until the
121 ETHREAD structure is being freed */
122 }
123 }
124
125 VOID
126 STDCALL
127 DumpEspData(ULONG Esp, ULONG ThLimit, ULONG ThStack, ULONG PcrLimit, ULONG PcrStack, ULONG Esp0)
128 {
129 DPRINT1("Current Esp: %p\n Thread Stack Limit: %p\n Thread Stack: %p\n Pcr Limit: %p, Pcr Stack: %p\n Esp0 :%p\n",Esp, ThLimit, ThStack, PcrLimit, PcrStack, Esp0) ;
130 }
131
132 PVOID
133 STDCALL
134 PsAllocateCallbackStack(ULONG StackSize)
135 {
136 PVOID KernelStack = NULL;
137 NTSTATUS Status;
138 PMEMORY_AREA StackArea;
139 ULONG i, j;
140 PHYSICAL_ADDRESS BoundaryAddressMultiple;
141 PPFN_TYPE Pages = alloca(sizeof(PFN_TYPE) * (StackSize /PAGE_SIZE));
142
143 DPRINT1("PsAllocateCallbackStack\n");
144 BoundaryAddressMultiple.QuadPart = 0;
145 StackSize = PAGE_ROUND_UP(StackSize);
146 MmLockAddressSpace(MmGetKernelAddressSpace());
147 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
148 MEMORY_AREA_KERNEL_STACK,
149 &KernelStack,
150 StackSize,
151 PAGE_READWRITE,
152 &StackArea,
153 FALSE,
154 0,
155 BoundaryAddressMultiple);
156 MmUnlockAddressSpace(MmGetKernelAddressSpace());
157 if (!NT_SUCCESS(Status))
158 {
159 DPRINT1("Failed to create thread stack\n");
160 return(NULL);
161 }
162 for (i = 0; i < (StackSize / PAGE_SIZE); i++)
163 {
164 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Pages[i]);
165 if (!NT_SUCCESS(Status))
166 {
167 for (j = 0; j < i; j++)
168 {
169 MmReleasePageMemoryConsumer(MC_NPPOOL, Pages[j]);
170 }
171 return(NULL);
172 }
173 }
174 Status = MmCreateVirtualMapping(NULL,
175 KernelStack,
176 PAGE_READWRITE,
177 Pages,
178 StackSize / PAGE_SIZE);
179 if (!NT_SUCCESS(Status))
180 {
181 for (i = 0; i < (StackSize / PAGE_SIZE); i++)
182 {
183 MmReleasePageMemoryConsumer(MC_NPPOOL, Pages[i]);
184 }
185 return(NULL);
186 }
187 DPRINT1("PsAllocateCallbackStack %x\n", KernelStack);
188 return(KernelStack);
189 }
190
191 NTSTATUS
192 STDCALL
193 NtW32Call(IN ULONG RoutineIndex,
194 IN PVOID Argument,
195 IN ULONG ArgumentLength,
196 OUT PVOID* Result OPTIONAL,
197 OUT PULONG ResultLength OPTIONAL)
198 {
199 NTSTATUS CallbackStatus;
200
201 DPRINT("NtW32Call(RoutineIndex %d, Argument %X, ArgumentLength %d)\n",
202 RoutineIndex, Argument, ArgumentLength);
203
204 /* FIXME: SEH!!! */
205
206 /* Call kernel function */
207 CallbackStatus = KeUserModeCallback(RoutineIndex,
208 Argument,
209 ArgumentLength,
210 Result,
211 ResultLength);
212
213 /* Return the result */
214 return(CallbackStatus);
215 }
216
217 #ifndef ALEX_CB_REWRITE
218 NTSTATUS STDCALL
219 NtCallbackReturn (PVOID Result,
220 ULONG ResultLength,
221 NTSTATUS Status)
222 {
223 PULONG OldStack;
224 PETHREAD Thread;
225 PNTSTATUS CallbackStatus;
226 PULONG CallerResultLength;
227 PVOID* CallerResult;
228 PVOID InitialStack;
229 PVOID StackBase;
230 ULONG_PTR StackLimit;
231 KIRQL oldIrql;
232 PNTW32CALL_SAVED_STATE State;
233 PKTRAP_FRAME SavedTrapFrame;
234 PVOID SavedCallbackStack;
235 PVOID SavedExceptionStack;
236
237 PAGED_CODE();
238
239 Thread = PsGetCurrentThread();
240 if (Thread->Tcb.CallbackStack == NULL)
241 {
242 return(STATUS_NO_CALLBACK_ACTIVE);
243 }
244
245 OldStack = (PULONG)Thread->Tcb.CallbackStack;
246
247 /*
248 * Get the values that NtW32Call left on the inactive stack for us.
249 */
250 State = (PNTW32CALL_SAVED_STATE)OldStack[0];
251 CallbackStatus = State->CallbackStatus;
252 CallerResultLength = State->CallerResultLength;
253 CallerResult = State->CallerResult;
254 InitialStack = State->SavedInitialStack;
255 StackBase = State->SavedStackBase;
256 StackLimit = State->SavedStackLimit;
257 SavedTrapFrame = State->SavedTrapFrame;
258 SavedCallbackStack = State->SavedCallbackStack;
259 SavedExceptionStack = State->SavedExceptionStack;
260
261 /*
262 * Copy the callback status and the callback result to NtW32Call
263 */
264 *CallbackStatus = Status;
265 if (CallerResult != NULL && CallerResultLength != NULL)
266 {
267 if (Result == NULL)
268 {
269 *CallerResultLength = 0;
270 }
271 else
272 {
273 *CallerResultLength = min(ResultLength, *CallerResultLength);
274 RtlCopyMemory(*CallerResult, Result, *CallerResultLength);
275 }
276 }
277
278 /*
279 * Restore the old stack.
280 */
281 KeRaiseIrql(HIGH_LEVEL, &oldIrql);
282 if ((Thread->Tcb.NpxState & NPX_STATE_VALID) &&
283 &Thread->Tcb != KeGetCurrentPrcb()->NpxThread)
284 {
285 RtlCopyMemory((char*)InitialStack - sizeof(FX_SAVE_AREA),
286 (char*)Thread->Tcb.InitialStack - sizeof(FX_SAVE_AREA),
287 sizeof(FX_SAVE_AREA));
288 }
289 Thread->Tcb.InitialStack = InitialStack;
290 Thread->Tcb.StackBase = StackBase;
291 Thread->Tcb.StackLimit = StackLimit;
292 Thread->Tcb.TrapFrame = SavedTrapFrame;
293 Thread->Tcb.CallbackStack = SavedCallbackStack;
294 KeGetCurrentKPCR()->TSS->Esp0 = (ULONG)SavedExceptionStack;
295 KeStackSwitchAndRet((PVOID)(OldStack + 1));
296
297 /* Should never return. */
298 KEBUGCHECK(0);
299 return(STATUS_UNSUCCESSFUL);
300 }
301 #endif
302 /* EOF */