From ba24debdaf0ad2b5fe2eed6d9540dd2d87a64790 Mon Sep 17 00:00:00 2001 From: mlankhorst Date: Wed, 3 Dec 2008 15:36:11 +0100 Subject: [PATCH] server: Add support for 64-bits client/server --- dlls/ntdll/server.c | 21 +++++++++++++++++---- server/protocol.def | 32 ++++++++++++++++++++++++-------- server/request.c | 24 ++++++++++++++++++++++-- server/thread.c | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 94 insertions(+), 20 deletions(-) diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index fd154ff8f2c..4af510387cf 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; @@ -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; } diff --git a/server/protocol.def b/server/protocol.def index a4c154c333b..bcac6267f5f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 + diff --git a/server/request.c b/server/request.c index d2aebb310b1..d39d879d345 100644 --- a/server/request.c +++ b/server/request.c @@ -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 ); diff --git a/server/thread.c b/server/thread.c index 1eeb59ffce8..d494736d28f 100644 --- a/server/thread.c +++ b/server/thread.c @@ -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, ¤t->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: -- 2.11.4.GIT