server: Add support for 64-bits client/server
authormlankhorst <mlankhorst@dhcp-172-29-61-127.smo.corp.google.com>
Wed, 3 Dec 2008 14:36:11 +0000 (3 15:36 +0100)
committerMaarten Lankhorst <m.b.lankhorst@gmail.com>
Sat, 27 Dec 2008 20:18:36 +0000 (27 21:18 +0100)
dlls/ntdll/server.c
server/protocol.def
server/request.c
server/thread.c

index fd154ff..4af5103 100644 (file)
@@ -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;
@@ -1038,19 +1039,27 @@ size_t server_init_thread( int unix_pid, int unix_tid, void *entry_point )
     {
         req->unix_pid    = unix_pid;
         req->unix_tid    = unix_tid;
-        req->teb         = NtCurrentTeb();
-        req->peb         = NtCurrentTeb()->Peb;
-        req->entry       = entry_point;
-        req->ldt_copy    = &wine_ldt_copy;
+        req->teb         = (int)(long)NtCurrentTeb();
+        req->peb         = (int)(long)NtCurrentTeb()->Peb;
+        req->entry       = (int)(long)entry_point;
+        req->ldt_copy    = (int)(long)&wine_ldt_copy;
+#ifdef _WIN64
+        req->teb_high    = (int)(((long)NtCurrentTeb()) >> 32L);
+        req->peb_high    = (int)(((long)NtCurrentTeb()->Peb) >> 32L);
+        req->entry_high  = (int)(((long)entry_point) >> 32L);
+        req->ldt_copy_high= (int)(((long)&wine_ldt_copy) >> 32L);
+#endif
         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 +1071,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\n",
+                               (int)sizeof(void*)*8, pointer_bytes*8 );
     return info_size;
 }
index a4c154c..bcac626 100644 (file)
@@ -60,9 +60,18 @@ 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 */
+    /* For 64-bits future support,
+     * the structure is larger than it needs to be
+     * 3 int's are used by the header, so with this change, you can arguably
+     * put in the arguments in any way you like
+     */
+    long pad1[12];
+    int pad2[4];
 };
 
+#define REQ_SIZE_64 (sizeof(__int64) * 12 + sizeof(int) * 4)
+#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 */
 
@@ -534,19 +543,25 @@ typedef union
 @REQ(init_thread)
     int          unix_pid;     /* Unix pid of new thread */
     int          unix_tid;     /* Unix tid of new thread */
-    int          debug_level;  /* new debug level */
-    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) */
-    void*        ldt_copy;     /* address of LDT copy (in thread address space) */
+    short int    debug_level;  /* new debug level */
+    short int    pointer_bytes;/* Amount of bytes in a pointer (for the client) */
+    int          teb;          /* TEB of new thread (in thread address space) */
+    int          peb;          /* address of PEB (in thread address space) */
+    int          entry;        /* thread entry point (in thread address space) */
+    int          ldt_copy;     /* address of LDT copy (in thread address space) */
     int          reply_fd;     /* fd for reply pipe */
     int          wait_fd;      /* fd for blocking calls pipe */
+    int          teb_high;     /* upper 32-bits of TEB */
+    int          peb_high;     /* upper 32-bits op PEB */
+    int          entry_high;   /* upper 32-bits of entry point */
+    int          ldt_copy_high;/* upper 32-bits of ldt copy high */
 @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 */
+    timeout_t    server_start; /* swapped with info size for 64-bits alignment*/
+    data_size_t  info_size;    /* swapped with server_start for alignment */
     int          version;      /* protocol version */
+    int          pointer_bytes;/* Amount of bytes in a pointer (for the server) */
 @END
 
 
@@ -3094,3 +3109,4 @@ enum message_type
     unsigned int   alpha;         /* alpha (0..255) */
     unsigned int   flags;         /* LWA_* flags */
 @END
+
index d2aebb3..d39d879 100644 (file)
@@ -314,8 +314,20 @@ 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 (sizeof(thread->req) == REQ_SIZE_64 && ret == REQ_SIZE_32)
+        {
+            /* Uh oh, we received a partial read, not an error per se, if
+             * we were connecting a 32-bit client to a 64-bit server
+             */
+            if (thread->req.request_header.req == REQ_init_thread &&
+                thread->req.init_thread_request.pointer_bytes != sizeof(void *))
+            {
+                /* Do nothing, this is a 32-bits client */
+            }
+            else
+                goto error;
+        }
         if (!(thread->req_toread = thread->req.request_header.request_size))
         {
             /* no data, handle request at once */
@@ -744,6 +756,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 );
index 1eeb59f..d494736 100644 (file)
@@ -1011,7 +1011,8 @@ 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 wait_fd = -1;
+    void *teb, *peb, *ldt_copy, *entry;
 
     if (current->reply_fd)  /* already initialised */
     {
@@ -1025,6 +1026,29 @@ DECL_HANDLER(init_thread)
     reply_fd = -1;
     if (!current->reply_fd) goto error;
 
+    /* The version of wine is too old, or a different-sized binary was trying
+     * to connect
+     */
+    if (req->pointer_bytes != sizeof(void *))
+    {
+        reply->version = SERVER_PROTOCOL_VERSION;
+        reply->pointer_bytes = sizeof(void *);
+        return;
+    }
+
+#ifndef _WIN64
+    teb = (void *)(long)req->teb;
+    peb = (void *)(long)req->peb;
+    ldt_copy = (void *)(long)req->ldt_copy;
+    entry = (void *)(long)req->entry;
+#else
+    teb = (void *)(((long)req->teb) + (((long)req->teb_high) << 32L));
+    peb = (void *)(((long)req->teb) + (((long)req->peb_high) << 32L));
+    ldt_copy = (void *)(((long)req->ldt_copy) + (((long)req->ldt_copy_high) << 32L));
+    entry = (void *)(((long)req->entry) + (((long)req->entry_high) << 32L));
+#endif
+
+    wait_fd = thread_get_inflight_fd( current, req->wait_fd );
     if (wait_fd == -1)
     {
         set_error( STATUS_TOO_MANY_OPENED_FILES );  /* most likely reason */
@@ -1033,7 +1057,7 @@ 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))
+    if (!is_valid_address(teb) || !is_valid_address(peb) || !is_valid_address(ldt_copy))
     {
         set_error( STATUS_INVALID_PARAMETER );
         return;
@@ -1041,13 +1065,13 @@ DECL_HANDLER(init_thread)
 
     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,7 +1079,7 @@ 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 );
 
@@ -1063,6 +1087,7 @@ DECL_HANDLER(init_thread)
     reply->tid     = get_thread_id( current );
     reply->version = SERVER_PROTOCOL_VERSION;
     reply->server_start = server_start_time;
+    reply->pointer_bytes = sizeof(void *);
     return;
 
  error: