xref: /reactos/win32ss/user/ntuser/csr.c (revision 84344399)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Interface between Win32k and USERSRV
5  * FILE:             win32ss/user/ntuser/csr.c
6  * PROGRAMMER:       Hermes Belusca-Maito (hermes.belusca@sfr.fr), based on
7  *                   the original code by Ge van Geldorp (ge@gse.nl) and by
8  *                   the CSR code in NTDLL.
9  */
10 
11 #include <win32k.h>
12 
13 DBG_DEFAULT_CHANNEL(UserCsr);
14 
15 PEPROCESS gpepCSRSS = NULL;
16 PVOID CsrApiPort = NULL;
17 DWORD gdwPendingSystemThreads = 0;
18 
19 VOID
20 InitCsrProcess(VOID /*IN PEPROCESS CsrProcess*/)
21 {
22     /* Save the EPROCESS of CSRSS */
23     gpepCSRSS = PsGetCurrentProcess();
24     // gpepCSRSS = CsrProcess;
25     ObReferenceObject(gpepCSRSS);
26 }
27 
28 VOID
29 ResetCsrProcess(VOID)
30 {
31     if (gpepCSRSS)
32         ObDereferenceObject(gpepCSRSS);
33 
34     gpepCSRSS = NULL;
35 }
36 
37 NTSTATUS
38 InitCsrApiPort(IN HANDLE CsrPortHandle)
39 {
40     NTSTATUS Status;
41 
42     Status = ObReferenceObjectByHandle(CsrPortHandle,
43                                        0,
44                                        /* * */LpcPortObjectType, // or NULL,
45                                        UserMode,
46                                        &CsrApiPort,
47                                        NULL);
48     if (!NT_SUCCESS(Status))
49     {
50         CsrApiPort = NULL;
51         ERR("Failed to set CSR API Port.\n");
52     }
53 
54     return Status;
55 }
56 
57 VOID
58 ResetCsrApiPort(VOID)
59 {
60     if (CsrApiPort)
61         ObDereferenceObject(CsrApiPort);
62 
63     CsrApiPort = NULL;
64 }
65 
66 /*
67  * Function copied from ntdll/csr/connect.c::CsrClientCallServer
68  * and adapted for kernel-mode.
69  *
70  * NOTE: This is really a co_* function!
71  */
72 NTSTATUS
73 NTAPI
74 CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage,
75                     IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL,
76                     IN CSR_API_NUMBER ApiNumber,
77                     IN ULONG DataLength)
78 {
79     NTSTATUS Status;
80 #if 0
81     ULONG PointerCount;
82     PULONG_PTR OffsetPointer;
83 #endif
84 
85     /* Do we have a connection to CSR yet? */
86     if (!CsrApiPort)
87         return STATUS_INVALID_PORT_HANDLE;
88 
89     /* Fill out the Port Message Header */
90     ApiMessage->Header.u2.ZeroInit = 0;
91     ApiMessage->Header.u1.s1.TotalLength = FIELD_OFFSET(CSR_API_MESSAGE, Data) + DataLength;
92     ApiMessage->Header.u1.s1.DataLength = ApiMessage->Header.u1.s1.TotalLength -
93         sizeof(ApiMessage->Header);
94 
95     /* Fill out the CSR Header */
96     ApiMessage->ApiNumber = ApiNumber;
97     ApiMessage->CsrCaptureData = NULL;
98 
99     TRACE("API: %lx, u1.s1.DataLength: %x, u1.s1.TotalLength: %x\n",
100           ApiNumber,
101           ApiMessage->Header.u1.s1.DataLength,
102           ApiMessage->Header.u1.s1.TotalLength);
103 
104 #if 0
105     /* Check if we got a Capture Buffer */
106     if (CaptureBuffer)
107     {
108         /*
109          * We have to convert from our local (client) view
110          * to the remote (server) view.
111          */
112         ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER)
113             ((ULONG_PTR)CaptureBuffer + CsrPortMemoryDelta);
114 
115         /* Lock the buffer. */
116         CaptureBuffer->BufferEnd = NULL;
117 
118         /*
119          * Each client pointer inside the CSR message is converted into
120          * a server pointer, and each pointer to these message pointers
121          * is converted into an offset.
122          */
123         PointerCount  = CaptureBuffer->PointerCount;
124         OffsetPointer = CaptureBuffer->PointerOffsetsArray;
125         while (PointerCount--)
126         {
127             if (*OffsetPointer != 0)
128             {
129                 *(PULONG_PTR)*OffsetPointer += CsrPortMemoryDelta;
130                 *OffsetPointer -= (ULONG_PTR)ApiMessage;
131             }
132             ++OffsetPointer;
133         }
134     }
135 #endif
136 
137     UserLeaveCo();
138 
139     /* Send the LPC Message */
140 
141     // The wait logic below is subject to change in the future. One can
142     // imagine adding an external parameter to CsrClientCallServer, or write
143     // two versions of CsrClientCallServer, synchronous and asynchronous.
144     if (PsGetCurrentProcess() == gpepCSRSS)
145     {
146         Status = LpcRequestPort(CsrApiPort,
147                                 &ApiMessage->Header);
148     }
149     else
150     {
151         Status = LpcRequestWaitReplyPort(CsrApiPort,
152                                          &ApiMessage->Header,
153                                          &ApiMessage->Header);
154     }
155 
156     UserEnterCo();
157 
158 #if 0
159     /* Check if we got a Capture Buffer */
160     if (CaptureBuffer)
161     {
162         /*
163          * We have to convert back from the remote (server) view
164          * to our local (client) view.
165          */
166         ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER)
167             ((ULONG_PTR)ApiMessage->CsrCaptureData - CsrPortMemoryDelta);
168 
169         /*
170          * Convert back the offsets into pointers to CSR message
171          * pointers, and convert back these message server pointers
172          * into client pointers.
173          */
174         PointerCount  = CaptureBuffer->PointerCount;
175         OffsetPointer = CaptureBuffer->PointerOffsetsArray;
176         while (PointerCount--)
177         {
178             if (*OffsetPointer != 0)
179             {
180                 *OffsetPointer += (ULONG_PTR)ApiMessage;
181                 *(PULONG_PTR)*OffsetPointer -= CsrPortMemoryDelta;
182             }
183             ++OffsetPointer;
184         }
185     }
186 #endif
187 
188     /* Check for success */
189     if (!NT_SUCCESS(Status))
190     {
191         /* We failed. Overwrite the return value with the failure. */
192         ERR("LPC Failed: %lx\n", Status);
193         ApiMessage->Status = Status;
194     }
195 
196     /* Return the CSR Result */
197     TRACE("Got back: 0x%lx\n", ApiMessage->Status);
198     return ApiMessage->Status;
199 }
200 
201 /*
202  * UserSystemThreadProc
203  *
204  * Called form dedicated thread in CSRSS. RIT is started in context of this
205  * thread because it needs valid Win32 process with TEB initialized.
206  */
207 DWORD UserSystemThreadProc(BOOL bRemoteProcess)
208 {
209     DWORD Type;
210 
211     if (!gdwPendingSystemThreads)
212     {
213         ERR("gdwPendingSystemThreads is 0!\n");
214         return 0;
215     }
216 
217     /* Decide which thread this will be */
218     if (gdwPendingSystemThreads & ST_RIT)
219         Type = ST_RIT;
220     else if (gdwPendingSystemThreads & ST_DESKTOP_THREAD)
221         Type = ST_DESKTOP_THREAD;
222     else
223         Type = ST_GHOST_THREAD;
224 
225     ASSERT(Type);
226 
227     /* We will handle one of these threads right here so unmark it as pending */
228     gdwPendingSystemThreads &= ~Type;
229 
230     UserLeave();
231 
232     TRACE("UserSystemThreadProc: %d\n", Type);
233 
234     switch (Type)
235     {
236         case ST_RIT: RawInputThreadMain(); break;
237         case ST_DESKTOP_THREAD: DesktopThreadMain(); break;
238         case ST_GHOST_THREAD: UserGhostThreadEntry(); break;
239         default: ERR("Wrong type: %x\n", Type);
240     }
241 
242     UserEnterShared();
243 
244     return 0;
245 }
246 
247 BOOL UserCreateSystemThread(DWORD Type)
248 {
249     USER_API_MESSAGE ApiMessage;
250     PUSER_CREATE_SYSTEM_THREAD pCreateThreadRequest = &ApiMessage.Data.CreateSystemThreadRequest;
251 
252     TRACE("UserCreateSystemThread: %d\n", Type);
253 
254     ASSERT(UserIsEnteredExclusive());
255 
256     if (gdwPendingSystemThreads & Type)
257     {
258         ERR("System thread 0x%x already pending for creation\n", Type);
259         return TRUE;
260     }
261 
262     /* We can't pass a parameter to the new thread so mark what the new thread needs to do */
263     gdwPendingSystemThreads |= Type;
264 
265     /* Ask winsrv to create a new system thread. This new thread will enter win32k again calling UserSystemThreadProc */
266     pCreateThreadRequest->bRemote = FALSE;
267     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
268                         NULL,
269                         CSR_CREATE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpCreateSystemThreads),
270                         sizeof(USER_CREATE_SYSTEM_THREAD));
271     if (!NT_SUCCESS(ApiMessage.Status))
272     {
273         ERR("Csr call failed!\n");
274         return FALSE;
275     }
276 
277     return TRUE;
278 }
279 
280 /* EOF */
281