[PATCH] server: Add support for 64-bits

mlankhorst mlankhorst at dhcp-172-29-61-127.smo.corp.google.com
Tue Dec 2 07:06:49 CST 2008


---
 dlls/ntdll/server.c |    7 +++
 server/protocol.def |   12 +++-
 server/request.c    |   14 +++++-
 server/thread.c     |  137 +++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 156 insertions(+), 14 deletions(-)

diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index 64d9a8b..012d5e7 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -1008,6 +1008,7 @@ size_t server_init_thread( int unix_pid, int unix_tid, void *entry_point )
     int reply_pipe[2];
     struct sigaction sig_act;
     size_t info_size;
+    int pointer_bytes;
 
     sig_act.sa_handler = SIG_IGN;
     sig_act.sa_flags   = 0;
@@ -1045,12 +1046,14 @@ size_t server_init_thread( int unix_pid, int unix_tid, void *entry_point )
         req->reply_fd    = reply_pipe[1];
         req->wait_fd     = ntdll_get_thread_data()->wait_fd[1];
         req->debug_level = (TRACE_ON(server) != 0);
+        req->pointer_bytes= sizeof(void *);
         ret = wine_server_call( req );
         NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid);
         NtCurrentTeb()->ClientId.UniqueThread  = ULongToHandle(reply->tid);
         info_size         = reply->info_size;
         version           = reply->version;
         server_start_time = reply->server_start;
+        pointer_bytes     = reply->pointer_bytes;
     }
     SERVER_END_REQ;
 
@@ -1062,5 +1065,9 @@ size_t server_init_thread( int unix_pid, int unix_tid, void *entry_point )
                                "Or maybe the wrong wineserver is still running?\n",
                                version, SERVER_PROTOCOL_VERSION,
                                (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
+    if (sizeof(void*) != pointer_bytes)
+        server_protocol_error( "Wineserver doesn't support %d bits binaries,\n",
+                               "instead it was built for %d bits binaries",
+                               (int)sizeof(void*)*8, pointer_bytes*8 );
     return info_size;
 }
diff --git a/server/protocol.def b/server/protocol.def
index e0537bf..4a98832 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -57,9 +57,13 @@ struct reply_header
 /* this is used to construct the generic_request union */
 struct request_max_size
 {
-    int pad[16]; /* the max request size is 16 ints */
+    long pad1[6]; /* request is 6 handles, and 10 ints */
+    int pad2[10];
 };
 
+#define REQ_SIZE_64 (sizeof(__int64) * 6 + sizeof(int) * 10)
+#define REQ_SIZE_32 (sizeof(int) * 16)
+
 #define FIRST_USER_HANDLE 0x0020  /* first possible value for low word of user handle */
 #define LAST_USER_HANDLE  0xffef  /* last possible value for low word of user handle */
 
@@ -152,6 +156,7 @@ struct wake_up_reply
 
 /* NT-style timeout, in 100ns units, negative means relative timeout */
 typedef __int64 timeout_t;
+
 #define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff)
 
 /* structure returned in the list of window properties */
@@ -523,6 +528,7 @@ typedef union
     int          unix_pid;     /* Unix pid of new thread */
     int          unix_tid;     /* Unix tid of new thread */
     int          debug_level;  /* new debug level */
+    int          pointer_bytes;/* Amount of bytes in a pointer (of the client) */
     void*        teb;          /* TEB of new thread (in thread address space) */
     void*        peb;          /* address of PEB (in thread address space) */
     void*        entry;        /* thread entry point (in thread address space) */
@@ -532,12 +538,12 @@ typedef union
 @REPLY
     process_id_t pid;          /* process id of the new thread's process */
     thread_id_t  tid;          /* thread id of the new thread */
-    data_size_t  info_size;    /* total size of startup info */
     timeout_t    server_start; /* server start time */
+    data_size_t  info_size;    /* total size of startup info */
     int          version;      /* protocol version */
+    int          pointer_bytes;/* Amount of bytes in a pointer (of the server) */
 @END
 
-
 /* Terminate a process */
 @REQ(terminate_process)
     obj_handle_t handle;       /* process handle to terminate */
diff --git a/server/request.c b/server/request.c
index 8726e1c..cb08e35 100644
--- a/server/request.c
+++ b/server/request.c
@@ -314,8 +314,10 @@ void read_request( struct thread *thread )
 
     if (!thread->req_toread)  /* no pending request */
     {
-        if ((ret = read( get_unix_fd( thread->request_fd ), &thread->req,
-                         sizeof(thread->req) )) != sizeof(thread->req)) goto error;
+        ret = read( get_unix_fd( thread->request_fd ), &thread->req, sizeof(thread->req) );
+        if (ret != REQ_SIZE_64 && ret != REQ_SIZE_32)
+            goto error;
+
         if (!(thread->req_toread = thread->req.request_header.request_size))
         {
             /* no data, handle request at once */
@@ -744,6 +746,14 @@ void open_master_socket(void)
     assert( sizeof(union generic_request) == sizeof(struct request_max_size) );
     assert( sizeof(union generic_reply) == sizeof(struct request_max_size) );
 
+    /* Make sure REQ_SIZE_32 and REQ_SIZE_64 are of correct size */
+    if (sizeof(void *) == sizeof(int))
+        assert(sizeof(struct request_max_size) == REQ_SIZE_32);
+    else if (sizeof(void *) == sizeof(__int64))
+        assert(sizeof(struct request_max_size) == REQ_SIZE_64);
+    else
+        assert(0);
+
     if (!server_dir) fatal_error( "directory %s cannot be accessed\n", config_dir );
     if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s", config_dir );
     if ((config_dir_fd = open( ".", O_RDONLY )) == -1) fatal_perror( "open %s", config_dir );
diff --git a/server/thread.c b/server/thread.c
index 0c496db..9ee2eb3 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1006,12 +1006,123 @@ DECL_HANDLER(new_thread)
     }
 }
 
+/* Wineserver protocol <= 346 type init_thread request structure */
+struct init_thread_request_legacy32
+{
+    struct request_header __header;
+    int          unix_pid;
+    int          unix_tid;
+    int          debug_level;
+    int          teb;
+    int          peb;
+    int          entry;
+    int          ldt_copy;
+    int          reply_fd;
+    int          wait_fd;
+};
+
+/* Current type init_thread request structure, pointer size = 32 */
+struct init_thread_request32
+{
+    struct request_header __header;
+    int          unix_pid;
+    int          unix_tid;
+    int          debug_level;
+    int          pointer_bytes;
+    int          teb;
+    int          peb;
+    int          entry;
+    int          ldt_copy;
+    int          reply_fd;
+    int          wait_fd;
+};
+
+/* Current type init_thread request structure, pointer size = 64 */
+struct init_thread_request64
+{
+    struct request_header __header;
+    int          unix_pid;
+    int          unix_tid;
+    int          debug_level;
+    int          pointer_bytes;
+    __int64      teb;
+    __int64      peb;
+    __int64      entry;
+    __int64      ldt_copy;
+    int          reply_fd;
+    int          wait_fd;
+};
+
 /* initialize a new thread */
 DECL_HANDLER(init_thread)
 {
     struct process *process = current->process;
-    int reply_fd = thread_get_inflight_fd( current, req->reply_fd );
-    int wait_fd = thread_get_inflight_fd( current, req->wait_fd );
+    int reply_fd, wait_fd;
+    void *ldt_copy, *entry, *peb, *teb;
+
+    /* 64-bits wineserver with 32-bits interaction is not yet supported
+     * "fake" success, but return the version and pointer bytes
+     * The client will terminate itself after reading the wrong
+     * protocol version or because of the pointer size mismatch
+     */
+
+    /* First upconvert 'old' wineserver requests from pure 32-bits wine
+     */
+    if (req->pointer_bytes != sizeof(void *) && req->pointer_bytes > 8)
+    {
+        struct init_thread_request_legacy32 *reql =
+            (struct init_thread_request_legacy32 *)req;
+
+        wait_fd = reql->wait_fd;
+        reply_fd = reql->reply_fd;
+        ldt_copy = (void *)(long)reql->ldt_copy;
+        entry = (void *)(long)reql->entry;
+        peb = (void *)(long)reql->peb;
+        teb = (void *)(long)reql->teb;
+    }
+    /* Case where a 64-bits client tries to connect to 32-bits wineserver
+     * The pointer types will be invalid, but we continue anyway to make
+     * it possible for the 64-bits client to realize that the pointer type
+     * is wrong
+     */
+    else if (req->pointer_bytes > sizeof(void *))
+    {
+        struct init_thread_request64 *req64 =
+            (struct init_thread_request64 *)req;
+
+        wait_fd = req64->wait_fd;
+        reply_fd = req64->reply_fd;
+        ldt_copy = (void *)(long)req64->ldt_copy;
+        entry = (void *)(long)req64->entry;
+        peb = (void *)(long)req64->peb;
+        teb = (void *)(long)req64->teb;
+    }
+    /* Case where a 32-bits client tries to connect to a 64-bits wineserver */
+    else if (req->pointer_bytes < sizeof(void *))
+    {
+        struct init_thread_request32 *req32 =
+            (struct init_thread_request32 *)req;
+
+        wait_fd = req32->wait_fd;
+        reply_fd = req32->reply_fd;
+        ldt_copy = (void *)(long)req32->ldt_copy;
+        entry = (void *)(long)req32->entry;
+        peb = (void *)(long)req32->peb;
+        teb = (void *)(long)req32->teb;
+    }
+    /* XX-bits client converts to XX-bits server */
+    else
+    {
+        wait_fd = req->wait_fd;
+        reply_fd = req->reply_fd;
+        ldt_copy = req->ldt_copy;
+        entry = req->entry;
+        peb = req->peb;
+        teb = req->teb;
+    }
+
+    reply_fd = thread_get_inflight_fd( current, reply_fd );
+    wait_fd = thread_get_inflight_fd( current, wait_fd );
 
     if (current->reply_fd)  /* already initialised */
     {
@@ -1033,21 +1144,28 @@ DECL_HANDLER(init_thread)
     if (!(current->wait_fd  = create_anonymous_fd( &thread_fd_ops, wait_fd, &current->obj, 0 )))
         return;
 
-    if (!is_valid_address(req->teb) || !is_valid_address(req->peb) || !is_valid_address(req->ldt_copy))
+    /* Skip the validity checks if connecting a 64-bits client to 32-bits wineserver
+     * The client will realize its mistake, print an error about incompatibility
+     * and exit
+     */
+    if (req->pointer_bytes != 8 || sizeof(void *) != sizeof(int))
     {
-        set_error( STATUS_INVALID_PARAMETER );
-        return;
+        if (!is_valid_address(teb) || !is_valid_address(peb) || !is_valid_address(ldt_copy))
+        {
+            set_error( STATUS_INVALID_PARAMETER );
+            return;
+        }
     }
 
     current->unix_pid = req->unix_pid;
     current->unix_tid = req->unix_tid;
-    current->teb      = req->teb;
+    current->teb      = teb;
 
     if (!process->peb)  /* first thread, initialize the process too */
     {
         process->unix_pid = current->unix_pid;
-        process->peb      = req->peb;
-        process->ldt_copy = req->ldt_copy;
+        process->peb      = peb;
+        process->ldt_copy = ldt_copy;
         reply->info_size  = init_process( current );
     }
     else
@@ -1055,13 +1173,14 @@ DECL_HANDLER(init_thread)
         if (process->unix_pid != current->unix_pid)
             process->unix_pid = -1;  /* can happen with linuxthreads */
         if (current->suspend + process->suspend > 0) stop_thread( current );
-        generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, req->entry );
+        generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, entry );
     }
     debug_level = max( debug_level, req->debug_level );
 
     reply->pid     = get_process_id( process );
     reply->tid     = get_thread_id( current );
     reply->version = SERVER_PROTOCOL_VERSION;
+    reply->pointer_bytes = sizeof(void *);
     reply->server_start = server_start_time;
     return;
 
-- 
1.5.6.5


--------------030701000408010007050700--



More information about the wine-patches mailing list