Reintroduce CSR support for kernel mode, based on code from Ge that was wiped out in revision 58770, and by ntdll CSR code. Is needed for kernel to user-mode CSR callbacks.

For readers, I remind you the big callback picture in the Win32 subsystem:
- In Windows NT 3.1 and 3.51, USER and GDI was modeled against client/server model (USER32.DLL and WINSRV.DLL, and GDI32.DLL and GDISRV.DLL), all running in user mode (using the CSR API).
- Starting Windows NT 4.0 (and up), some USER and GDI parts were moved into kernel mode (in the WIN32K.SYS driver) to speedup communication. We get:
  * GDI32.DLL as the client, doing win32k system calls (kernel-mode system calls to win32k),
  * and USER32.DLL, WINSRV.DLL and WIN32K.SYS working in tandem, USER32.DLL being the client and {WINSRV.DLL, WIN32K.SYS} being the server.
    USER32.DLL can do win32k system calls or CSR calls to WINSRV.DLL (client to server calls). For server-to-server calls, we have WINSRV.DLL
    doing win32k system calls, or WIN32K.SYS doing CSR calls back to WINSRV.DLL . Also, there is the possibility for WIN32K.SYS to make user-mode
    callbacks to USER32.DLL.

svn path=/trunk/; revision=65817
This commit is contained in:
Hermès Bélusca-Maïto 2014-12-23 21:17:24 +00:00
parent eacca6fe3e
commit 56347a8b98
8 changed files with 231 additions and 82 deletions

View file

@ -105,6 +105,7 @@ list(APPEND SOURCE
user/ntuser/caret.c user/ntuser/caret.c
user/ntuser/class.c user/ntuser/class.c
user/ntuser/clipboard.c user/ntuser/clipboard.c
user/ntuser/csr.c
user/ntuser/defwnd.c user/ntuser/defwnd.c
user/ntuser/desktop.c user/ntuser/desktop.c
user/ntuser/display.c user/ntuser/display.c

View file

@ -1,91 +1,201 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem * PROJECT: ReactOS Win32k subsystem
* PURPOSE: Interface to CSRSS / USERSRV * PURPOSE: Interface between Win32k and USERSRV
* FILE: subsystems/win32/win32k/ntuser/csr.c * FILE: subsystems/win32/win32k/ntuser/csr.c
* PROGRAMER: Ge van Geldorp (ge@gse.nl) * PROGRAMER: Hermes Belusca-Maito (hermes.belusca@sfr.fr), based on
* the original code by Ge van Geldorp (ge@gse.nl) and by
* the CSR code in NTDLL.
*/ */
#include <win32k.h> #include <win32k.h>
static HANDLE WindowsApiPort = NULL; DBG_DEFAULT_CHANNEL(UserCsr);
// See gpepCSRSS in ntuser/ntuser.c and its initialization into NtUserInitialize()
PEPROCESS CsrProcess = NULL;
NTSTATUS FASTCALL PEPROCESS gpepCSRSS = NULL;
CsrInit(void) PVOID CsrApiPort = NULL;
VOID
InitCsrProcess(VOID /*IN PEPROCESS CsrProcess*/)
{ {
NTSTATUS Status; /* Save the EPROCESS of CSRSS */
UNICODE_STRING PortName; gpepCSRSS = PsGetCurrentProcess();
ULONG ConnectInfoLength; // gpepCSRSS = CsrProcess;
SECURITY_QUALITY_OF_SERVICE Qos; ObReferenceObject(gpepCSRSS);
RtlInitUnicodeString(&PortName, L"\\Windows\\ApiPort");
ConnectInfoLength = 0;
Qos.Length = sizeof(Qos);
Qos.ImpersonationLevel = SecurityDelegation;
Qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
Qos.EffectiveOnly = FALSE;
Status = ZwConnectPort(&WindowsApiPort,
&PortName,
&Qos,
NULL,
NULL,
NULL,
NULL,
&ConnectInfoLength);
if (!NT_SUCCESS(Status))
{
return Status;
}
CsrProcess = PsGetCurrentProcess();
return STATUS_SUCCESS;
} }
NTSTATUS FASTCALL VOID
co_CsrNotify(PCSR_API_MESSAGE Request) ResetCsrProcess(VOID)
{ {
NTSTATUS Status; if (gpepCSRSS)
PEPROCESS OldProcess; ObDereferenceObject(gpepCSRSS);
if (NULL == CsrProcess) gpepCSRSS = NULL;
{ }
return STATUS_INVALID_PORT_HANDLE;
}
Request->Header.u2.ZeroInit = 0; NTSTATUS
Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE); InitCsrApiPort(IN HANDLE CsrPortHandle)
Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE); {
NTSTATUS Status;
/* Switch to the process in which the WindowsApiPort handle is valid */ Status = ObReferenceObjectByHandle(CsrPortHandle,
OldProcess = PsGetCurrentProcess(); 0,
if (CsrProcess != OldProcess) /* * */LpcPortObjectType, // or NULL,
{ UserMode,
KeAttachProcess(&CsrProcess->Pcb); &CsrApiPort,
} NULL);
if (!NT_SUCCESS(Status))
{
CsrApiPort = NULL;
ERR("Failed to set CSR API Port.\n");
}
UserLeaveCo(); return Status;
}
Status = ZwRequestWaitReplyPort(WindowsApiPort, VOID
&Request->Header, ResetCsrApiPort(VOID)
&Request->Header); {
if (CsrApiPort)
ObDereferenceObject(CsrApiPort);
UserEnterCo(); CsrApiPort = NULL;
}
if (CsrProcess != OldProcess) /*
{ * Function copied from ntdll/csr/connect.c::CsrClientCallServer
KeDetachProcess(); * and adapted for kernel-mode.
} *
* NOTE: This is really a co_* function!
*/
NTSTATUS
NTAPI
CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage,
IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL,
IN CSR_API_NUMBER ApiNumber,
IN ULONG DataLength)
{
NTSTATUS Status;
#if 0
ULONG PointerCount;
PULONG_PTR OffsetPointer;
#endif
if (NT_SUCCESS(Status)) /* Do we have a connection to CSR yet? */
{ if (!CsrApiPort)
Status = Request->Status; return STATUS_INVALID_PORT_HANDLE;
}
return Status; /* Fill out the Port Message Header */
ApiMessage->Header.u2.ZeroInit = 0;
ApiMessage->Header.u1.s1.TotalLength = DataLength +
sizeof(CSR_API_MESSAGE) - sizeof(ApiMessage->Data); // FIELD_OFFSET(CSR_API_MESSAGE, Data) + DataLength;
ApiMessage->Header.u1.s1.DataLength = DataLength +
FIELD_OFFSET(CSR_API_MESSAGE, Data) - sizeof(ApiMessage->Header); // ApiMessage->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
/* Fill out the CSR Header */
ApiMessage->ApiNumber = ApiNumber;
ApiMessage->CsrCaptureData = NULL;
TRACE("API: %lx, u1.s1.DataLength: %x, u1.s1.TotalLength: %x\n",
ApiNumber,
ApiMessage->Header.u1.s1.DataLength,
ApiMessage->Header.u1.s1.TotalLength);
#if 0
/* Check if we got a Capture Buffer */
if (CaptureBuffer)
{
/*
* We have to convert from our local (client) view
* to the remote (server) view.
*/
ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER)
((ULONG_PTR)CaptureBuffer + CsrPortMemoryDelta);
/* Lock the buffer. */
CaptureBuffer->BufferEnd = NULL;
/*
* Each client pointer inside the CSR message is converted into
* a server pointer, and each pointer to these message pointers
* is converted into an offset.
*/
PointerCount = CaptureBuffer->PointerCount;
OffsetPointer = CaptureBuffer->PointerOffsetsArray;
while (PointerCount--)
{
if (*OffsetPointer != 0)
{
*(PULONG_PTR)*OffsetPointer += CsrPortMemoryDelta;
*OffsetPointer -= (ULONG_PTR)ApiMessage;
}
++OffsetPointer;
}
}
#endif
UserLeaveCo();
/* Send the LPC Message */
// The wait logic below is subject to change in the future. One can
// imagine adding an external parameter to CsrClientCallServer, or write
// two versions of CsrClientCallServer, synchronous and asynchronous.
if (PsGetCurrentProcess() == gpepCSRSS)
{
Status = LpcRequestPort(CsrApiPort,
&ApiMessage->Header);
}
else
{
Status = LpcRequestWaitReplyPort(CsrApiPort,
&ApiMessage->Header,
&ApiMessage->Header);
}
UserEnterCo();
#if 0
/* Check if we got a Capture Buffer */
if (CaptureBuffer)
{
/*
* We have to convert back from the remote (server) view
* to our local (client) view.
*/
ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER)
((ULONG_PTR)ApiMessage->CsrCaptureData - CsrPortMemoryDelta);
/*
* Convert back the offsets into pointers to CSR message
* pointers, and convert back these message server pointers
* into client pointers.
*/
PointerCount = CaptureBuffer->PointerCount;
OffsetPointer = CaptureBuffer->PointerOffsetsArray;
while (PointerCount--)
{
if (*OffsetPointer != 0)
{
*OffsetPointer += (ULONG_PTR)ApiMessage;
*(PULONG_PTR)*OffsetPointer -= CsrPortMemoryDelta;
}
++OffsetPointer;
}
}
#endif
/* Check for success */
if (!NT_SUCCESS(Status))
{
/* We failed. Overwrite the return value with the failure. */
ERR("LPC Failed: %lx\n", Status);
ApiMessage->Status = Status;
}
/* Return the CSR Result */
TRACE("Got back: 0x%lx\n", ApiMessage->Status);
return ApiMessage->Status;
} }
/* EOF */ /* EOF */

View file

@ -1,16 +1,35 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem * PROJECT: ReactOS Win32k subsystem
* PURPOSE: Interface to CSRSS / USERSRV * PURPOSE: Interface between Win32k and USERSRV
* FILE: subsystems/win32/win32k/ntuser/csr.h * FILE: subsystems/win32/win32k/ntuser/csr.h
* PROGRAMER: Ge van Geldorp (ge@gse.nl) * PROGRAMER: Hermes Belusca-Maito (hermes.belusca@sfr.fr), based on
* the original code by Ge van Geldorp (ge@gse.nl) and by
* the CSR code in NTDLL.
*/ */
#pragma once #pragma once
extern PEPROCESS CsrProcess; /* NDK Headers */
#include <ndk/lpcfuncs.h>
NTSTATUS FASTCALL CsrInit(void); /* CSRSS Header */
NTSTATUS FASTCALL co_CsrNotify(PCSR_API_MESSAGE Request); #include <csr/csr.h>
#include <win/winmsg.h>
extern PEPROCESS gpepCSRSS;
extern PVOID CsrApiPort;
VOID InitCsrProcess(VOID /*IN PEPROCESS CsrProcess*/);
VOID ResetCsrProcess(VOID);
NTSTATUS InitCsrApiPort(IN HANDLE CsrPortHandle);
VOID ResetCsrApiPort(VOID);
NTSTATUS
NTAPI
CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage,
IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL,
IN CSR_API_NUMBER ApiNumber,
IN ULONG DataLength);
/* EOF */ /* EOF */

View file

@ -724,18 +724,30 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
return Status; return Status;
} }
VOID NTAPI
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
// TODO: Do more cleanup!
ResetCsrApiPort();
ResetCsrProcess();
}
#ifdef _M_IX86 #ifdef _M_IX86
C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE); C_ASSERT(sizeof(SERVERINFO) <= PAGE_SIZE);
#endif #endif
// Return on failure // Return on failure
#define NT_ROF(x) \ #define NT_ROF(x) \
{ \
Status = (x); \ Status = (x); \
if (!NT_SUCCESS(Status)) \ if (!NT_SUCCESS(Status)) \
{ \ { \
DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \ DPRINT1("Failed '%s' (0x%lx)\n", #x, Status); \
return Status; \ return Status; \
} } \
}
/* /*
* This definition doesn't work * This definition doesn't work
@ -744,8 +756,8 @@ INIT_FUNCTION
NTSTATUS NTSTATUS
APIENTRY APIENTRY
DriverEntry( DriverEntry(
IN PDRIVER_OBJECT DriverObject, IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath) IN PUNICODE_STRING RegistryPath)
{ {
NTSTATUS Status; NTSTATUS Status;
BOOLEAN Result; BOOLEAN Result;
@ -768,7 +780,9 @@ DriverEntry(
} }
hModuleWin = MmPageEntireDriver(DriverEntry); hModuleWin = MmPageEntireDriver(DriverEntry);
DPRINT("Win32k hInstance 0x%p!\n",hModuleWin); DPRINT("Win32k hInstance 0x%p!\n", hModuleWin);
DriverObject->DriverUnload = DriverUnload;
/* Register Object Manager Callbacks */ /* Register Object Manager Callbacks */
CalloutData.ProcessCallout = Win32kProcessCallback; CalloutData.ProcessCallout = Win32kProcessCallback;

View file

@ -939,9 +939,13 @@ NtUserSetInformationThread(IN HANDLE ThreadHandle,
case UserThreadCsrApiPort: case UserThreadCsrApiPort:
{ {
ERR("Set CSR API Port for Win32k\n"); ERR("Set CSR API Port for Win32k\n");
STUB;
// Return success to make usersrv happy. if (ThreadInformationLength != sizeof(HANDLE))
Status = STATUS_SUCCESS; {
Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
Status = InitCsrApiPort(*(PHANDLE)ThreadInformation);
break; break;
} }

View file

@ -19,7 +19,6 @@ ATOM AtomLayer; // Window Layer atom.
ATOM AtomFlashWndState; // Window Flash State atom. ATOM AtomFlashWndState; // Window Flash State atom.
HINSTANCE hModClient = NULL; HINSTANCE hModClient = NULL;
BOOL ClientPfnInit = FALSE; BOOL ClientPfnInit = FALSE;
PEPROCESS gpepCSRSS = NULL;
ATOM gaGuiConsoleWndClass; ATOM gaGuiConsoleWndClass;
/* PRIVATE FUNCTIONS *********************************************************/ /* PRIVATE FUNCTIONS *********************************************************/
@ -175,7 +174,7 @@ NtUserInitialize(
UserEnterExclusive(); UserEnterExclusive();
/* Save the EPROCESS of CSRSS */ /* Save the EPROCESS of CSRSS */
gpepCSRSS = PsGetCurrentProcess(); InitCsrProcess(/*PsGetCurrentProcess()*/);
// Initialize Power Request List (use hPowerRequestEvent). // Initialize Power Request List (use hPowerRequestEvent).
// Initialize Media Change (use hMediaRequestEvent). // Initialize Media Change (use hMediaRequestEvent).

View file

@ -14,7 +14,6 @@ extern PTHREADINFO gptiCurrent;
extern PPROCESSINFO gppiList; extern PPROCESSINFO gppiList;
extern PPROCESSINFO ppiScrnSaver; extern PPROCESSINFO ppiScrnSaver;
extern PPROCESSINFO gppiInputProvider; extern PPROCESSINFO gppiInputProvider;
extern PEPROCESS gpepCSRSS;
extern ATOM gaGuiConsoleWndClass; extern ATOM gaGuiConsoleWndClass;
INIT_FUNCTION NTSTATUS NTAPI InitUserImpl(VOID); INIT_FUNCTION NTSTATUS NTAPI InitUserImpl(VOID);

View file

@ -26,7 +26,10 @@
#define DBG_ENABLE_EVENT_LOGGING 0 #define DBG_ENABLE_EVENT_LOGGING 0
#define DBG_ENABLE_SERVICE_HOOKS 0 #define DBG_ENABLE_SERVICE_HOOKS 0
/* Misc headers */ /* CSRSS Interface */
#include "user/ntuser/csr.h"
/* Misc headers */
#include "user/ntuser/win32kdebug.h" #include "user/ntuser/win32kdebug.h"
#include "user/ntuser/mmcopy.h" #include "user/ntuser/mmcopy.h"
#include "user/ntuser/tags.h" #include "user/ntuser/tags.h"