08d84402105a696410b149efabcfed2ee1fab3c3
[reactos.git] / reactos / ntoskrnl / ps / win32.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/win32.c
5 * PURPOSE: Process Manager: Win32K Initialization and Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ****************************************************************/
10
11 #include <ntoskrnl.h>
12 #include <winerror.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ******************************************************************/
17
18 PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout = NULL;
19 PKWIN32_THREAD_CALLOUT PspW32ThreadCallout = NULL;
20 PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch = NULL;
21 extern PKWIN32_PARSEMETHOD_CALLOUT ExpWindowStationObjectParse;
22 extern PKWIN32_DELETEMETHOD_CALLOUT ExpWindowStationObjectDelete;
23 extern PKWIN32_DELETEMETHOD_CALLOUT ExpDesktopObjectDelete;
24 extern PKWIN32_POWEREVENT_CALLOUT PopEventCallout;
25
26 /* PRIVATE FUNCTIONS *********************************************************/
27
28 NTSTATUS
29 NTAPI
30 PsConvertToGuiThread(VOID)
31 {
32 ULONG_PTR NewStack;
33 PVOID OldStack;
34 PETHREAD Thread = PsGetCurrentThread();
35 PEPROCESS Process = PsGetCurrentProcess();
36 NTSTATUS Status;
37 PAGED_CODE();
38
39 /* Validate the previous mode */
40 if (KeGetPreviousMode() == KernelMode) return STATUS_INVALID_PARAMETER;
41
42 /* If no win32k, crashes later */
43 ASSERT(PspW32ProcessCallout != NULL);
44
45 /* Make sure win32k is here */
46 if (!PspW32ProcessCallout) return STATUS_ACCESS_DENIED;
47
48 /* Make sure it's not already win32 */
49 if (Thread->Tcb.ServiceTable != KeServiceDescriptorTable)
50 {
51 /* We're already a win32 thread */
52 return STATUS_ALREADY_WIN32;
53 }
54
55 /* Check if we don't already have a kernel-mode stack */
56 if (!Thread->Tcb.LargeStack)
57 {
58 /* We don't create one */
59 NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0);
60 if (!NewStack)
61 {
62 /* Panic in user-mode */
63 NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
64 return STATUS_NO_MEMORY;
65 }
66
67 /* We're about to switch stacks. Enter a guarded region */
68 KeEnterGuardedRegion();
69
70 /* Switch stacks */
71 OldStack = KeSwitchKernelStack((PVOID)NewStack,
72 (PVOID)(NewStack - KERNEL_STACK_SIZE));
73
74 /* Leave the guarded region */
75 KeLeaveGuardedRegion();
76
77 /* Delete the old stack */
78 MmDeleteKernelStack(OldStack, FALSE);
79 }
80
81 /* This check is bizare. Check out win32k later */
82 if (!Process->Win32Process)
83 {
84 /* Now tell win32k about us */
85 Status = PspW32ProcessCallout(Process, TRUE);
86 if (!NT_SUCCESS(Status)) return Status;
87 }
88
89 /* Set the new service table */
90 Thread->Tcb.ServiceTable = KeServiceDescriptorTableShadow;
91 ASSERT(Thread->Tcb.Win32Thread == 0);
92
93 /* Tell Win32k about our thread */
94 Status = PspW32ThreadCallout(Thread, PsW32ThreadCalloutInitialize);
95 if (!NT_SUCCESS(Status))
96 {
97 /* Revert our table */
98 Thread->Tcb.ServiceTable = KeServiceDescriptorTable;
99 }
100
101 /* Return status */
102 return Status;
103 }
104
105 /* PUBLIC FUNCTIONS **********************************************************/
106
107 /*
108 * @implemented
109 */
110 VOID
111 NTAPI
112 PsEstablishWin32Callouts(IN PWIN32_CALLOUTS_FPNS CalloutData)
113 {
114 /* Setup the callback pointers */
115 PspW32ProcessCallout = CalloutData->ProcessCallout;
116 PspW32ThreadCallout = CalloutData->ThreadCallout;
117 ExpWindowStationObjectParse = CalloutData->WindowStationParseProcedure;
118 ExpWindowStationObjectDelete = CalloutData->WindowStationDeleteProcedure;
119 ExpDesktopObjectDelete = CalloutData->DesktopDeleteProcedure;
120 PopEventCallout = CalloutData->PowerEventCallout;
121 KeGdiFlushUserBatch = CalloutData->BatchFlushRoutine;
122 }
123
124 NTSTATUS
125 NTAPI
126 NtW32Call(IN ULONG RoutineIndex,
127 IN PVOID Argument,
128 IN ULONG ArgumentLength,
129 OUT PVOID* Result,
130 OUT PULONG ResultLength)
131 {
132 PVOID RetResult;
133 ULONG RetResultLength;
134 NTSTATUS Status = STATUS_SUCCESS;
135 ASSERT(KeGetPreviousMode() != KernelMode);
136
137 /* Enter SEH for probing */
138 _SEH2_TRY
139 {
140 /* Probe arguments */
141 ProbeForWritePointer(Result);
142 ProbeForWriteUlong(ResultLength);
143 }
144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
145 {
146 /* Get exception code */
147 Status = _SEH2_GetExceptionCode();
148 }
149 _SEH2_END;
150
151 /* Make sure we got success */
152 if (NT_SUCCESS(Status))
153 {
154 /* Call kernel function */
155 Status = KeUserModeCallback(RoutineIndex,
156 Argument,
157 ArgumentLength,
158 &RetResult,
159 &RetResultLength);
160 if (NT_SUCCESS(Status))
161 {
162 /* Enter SEH for write back */
163 _SEH2_TRY
164 {
165 /* Return results to user mode */
166 *Result = RetResult;
167 *ResultLength = RetResultLength;
168 }
169 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
170 {
171 /* Get the exception code */
172 Status = _SEH2_GetExceptionCode();
173 }
174 _SEH2_END;
175 }
176 }
177
178 /* Return the result */
179 return Status;
180 }
181
182 /* EOF */