From c0319e0eabbad87a3e153c23f2461c881153b984 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 1 Jun 2020 13:40:25 +0200 Subject: [PATCH] ntdll: Move server wait functions to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/ntdll/critsection.c | 2 +- dlls/ntdll/exception.c | 4 +- dlls/ntdll/process.c | 2 +- dlls/ntdll/server.c | 449 ------------------------------- dlls/ntdll/sync.c | 12 +- dlls/ntdll/thread.c | 2 +- dlls/ntdll/unix/loader.c | 3 + dlls/ntdll/unix/server.c | 424 +++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_arm.c | 110 ++++++++ dlls/ntdll/unix/signal_arm64.c | 98 +++++++ dlls/ntdll/unix/signal_i386.c | 142 ++++++++++ dlls/ntdll/unix/signal_powerpc.c | 202 ++++++++++++++ dlls/ntdll/unix/signal_x86_64.c | 134 +++++++++ dlls/ntdll/unix/unix_private.h | 9 + dlls/ntdll/unixlib.h | 8 +- dlls/ntdll/virtual.c | 18 +- 16 files changed, 1149 insertions(+), 470 deletions(-) diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c index 71cc6c3f194..bfb7761d286 100644 --- a/dlls/ntdll/critsection.c +++ b/dlls/ntdll/critsection.c @@ -232,7 +232,7 @@ static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout ) time.QuadPart = timeout * (LONGLONG)-10000000; select_op.wait.op = SELECT_WAIT; select_op.wait.handles[0] = wine_server_obj_handle( sem ); - ret = server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time ); + ret = unix_funcs->server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time ); } return ret; } diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index fd1d7c6d641..c0309ab6dbb 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -114,7 +114,7 @@ void wait_suspend( CONTEXT *context ) int saved_errno = errno; /* wait with 0 timeout, will only return once the thread is no longer suspended */ - server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, context, NULL, NULL ); + unix_funcs->server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, context, NULL, NULL ); errno = saved_errno; } @@ -159,7 +159,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *con { select_op.wait.op = SELECT_WAIT; select_op.wait.handles[0] = handle; - server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, TIMEOUT_INFINITE, &exception_context, NULL, NULL ); + unix_funcs->server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, TIMEOUT_INFINITE, &exception_context, NULL, NULL ); SERVER_START_REQ( get_exception_status ) { diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index 1bef51b00b3..c066610ebca 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -1797,7 +1797,7 @@ NTSTATUS WINAPI DbgUiIssueRemoteBreakin( HANDLE process ) memset( &call, 0, sizeof(call) ); call.type = APC_BREAK_PROCESS; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status) return status; return result.break_process.status; } diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 175be4a327c..c7788b99e2d 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -116,32 +116,6 @@ timeout_t server_start_time = 0; /* time of server startup */ sigset_t server_block_set; /* signals to block during server calls */ -/*********************************************************************** - * server_protocol_error - */ -static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... ) -{ - va_list args; - - va_start( args, err ); - fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); - vfprintf( stderr, err, args ); - va_end( args ); - for (;;) unix_funcs->abort_thread(1); -} - - -/*********************************************************************** - * server_protocol_perror - */ -static DECLSPEC_NORETURN void server_protocol_perror( const char *err ) -{ - fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() ); - perror( err ); - for (;;) unix_funcs->abort_thread(1); -} - - /*********************************************************************** * wine_server_call (NTDLL.@) * @@ -190,429 +164,6 @@ void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sig } -/*********************************************************************** - * wait_select_reply - * - * Wait for a reply on the waiting pipe of the current thread. - */ -static int wait_select_reply( void *cookie ) -{ - int signaled; - struct wake_up_reply reply; - for (;;) - { - int ret; - ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) ); - if (ret == sizeof(reply)) - { - if (!reply.cookie) unix_funcs->abort_thread( reply.signaled ); /* thread got killed */ - if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled; - /* we stole another reply, wait for the real one */ - signaled = wait_select_reply( cookie ); - /* and now put the wrong one back in the pipe */ - for (;;) - { - ret = write( ntdll_get_thread_data()->wait_fd[1], &reply, sizeof(reply) ); - if (ret == sizeof(reply)) break; - if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret ); - if (errno == EINTR) continue; - server_protocol_perror("wakeup write"); - } - return signaled; - } - if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret ); - if (errno == EINTR) continue; - server_protocol_perror("wakeup read"); - } -} - - -static void invoke_apc( const user_apc_t *apc ) -{ - switch( apc->type ) - { - case APC_USER: - { - void (WINAPI *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR) = wine_server_get_ptr( apc->user.func ); - func( apc->user.args[0], apc->user.args[1], apc->user.args[2] ); - break; - } - case APC_TIMER: - { - void (WINAPI *func)(void*, unsigned int, unsigned int) = wine_server_get_ptr( apc->user.func ); - func( wine_server_get_ptr( apc->user.args[1] ), - (DWORD)apc->timer.time, (DWORD)(apc->timer.time >> 32) ); - break; - } - default: - server_protocol_error( "get_apc_request: bad type %d\n", apc->type ); - break; - } -} - -/*********************************************************************** - * invoke_apc - * - * Invoke a single APC. - * - */ -static void invoke_system_apc( const apc_call_t *call, apc_result_t *result ) -{ - SIZE_T size, bits; - void *addr; - - memset( result, 0, sizeof(*result) ); - - switch (call->type) - { - case APC_NONE: - break; - case APC_ASYNC_IO: - { - IO_STATUS_BLOCK *iosb = wine_server_get_ptr( call->async_io.sb ); - NTSTATUS (**user)(void *, IO_STATUS_BLOCK *, NTSTATUS) = wine_server_get_ptr( call->async_io.user ); - result->type = call->type; - result->async_io.status = (*user)( user, iosb, call->async_io.status ); - if (result->async_io.status != STATUS_PENDING) - result->async_io.total = iosb->Information; - break; - } - case APC_VIRTUAL_ALLOC: - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_alloc.addr ); - size = call->virtual_alloc.size; - bits = call->virtual_alloc.zero_bits; - if ((ULONG_PTR)addr == call->virtual_alloc.addr && size == call->virtual_alloc.size && - bits == call->virtual_alloc.zero_bits) - { - result->virtual_alloc.status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, bits, &size, - call->virtual_alloc.op_type, - call->virtual_alloc.prot ); - result->virtual_alloc.addr = wine_server_client_ptr( addr ); - result->virtual_alloc.size = size; - } - else result->virtual_alloc.status = STATUS_WORKING_SET_LIMIT_RANGE; - break; - case APC_VIRTUAL_FREE: - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_free.addr ); - size = call->virtual_free.size; - if ((ULONG_PTR)addr == call->virtual_free.addr && size == call->virtual_free.size) - { - result->virtual_free.status = NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, - call->virtual_free.op_type ); - result->virtual_free.addr = wine_server_client_ptr( addr ); - result->virtual_free.size = size; - } - else result->virtual_free.status = STATUS_INVALID_PARAMETER; - break; - case APC_VIRTUAL_QUERY: - { - MEMORY_BASIC_INFORMATION info; - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_query.addr ); - if ((ULONG_PTR)addr == call->virtual_query.addr) - result->virtual_query.status = NtQueryVirtualMemory( NtCurrentProcess(), - addr, MemoryBasicInformation, &info, - sizeof(info), NULL ); - else - result->virtual_query.status = STATUS_WORKING_SET_LIMIT_RANGE; - - if (result->virtual_query.status == STATUS_SUCCESS) - { - result->virtual_query.base = wine_server_client_ptr( info.BaseAddress ); - result->virtual_query.alloc_base = wine_server_client_ptr( info.AllocationBase ); - result->virtual_query.size = info.RegionSize; - result->virtual_query.prot = info.Protect; - result->virtual_query.alloc_prot = info.AllocationProtect; - result->virtual_query.state = info.State >> 12; - result->virtual_query.alloc_type = info.Type >> 16; - } - break; - } - case APC_VIRTUAL_PROTECT: - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_protect.addr ); - size = call->virtual_protect.size; - if ((ULONG_PTR)addr == call->virtual_protect.addr && size == call->virtual_protect.size) - { - result->virtual_protect.status = NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, - call->virtual_protect.prot, - &result->virtual_protect.prot ); - result->virtual_protect.addr = wine_server_client_ptr( addr ); - result->virtual_protect.size = size; - } - else result->virtual_protect.status = STATUS_INVALID_PARAMETER; - break; - case APC_VIRTUAL_FLUSH: - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_flush.addr ); - size = call->virtual_flush.size; - if ((ULONG_PTR)addr == call->virtual_flush.addr && size == call->virtual_flush.size) - { - result->virtual_flush.status = NtFlushVirtualMemory( NtCurrentProcess(), - (const void **)&addr, &size, 0 ); - result->virtual_flush.addr = wine_server_client_ptr( addr ); - result->virtual_flush.size = size; - } - else result->virtual_flush.status = STATUS_INVALID_PARAMETER; - break; - case APC_VIRTUAL_LOCK: - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_lock.addr ); - size = call->virtual_lock.size; - if ((ULONG_PTR)addr == call->virtual_lock.addr && size == call->virtual_lock.size) - { - result->virtual_lock.status = NtLockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 ); - result->virtual_lock.addr = wine_server_client_ptr( addr ); - result->virtual_lock.size = size; - } - else result->virtual_lock.status = STATUS_INVALID_PARAMETER; - break; - case APC_VIRTUAL_UNLOCK: - result->type = call->type; - addr = wine_server_get_ptr( call->virtual_unlock.addr ); - size = call->virtual_unlock.size; - if ((ULONG_PTR)addr == call->virtual_unlock.addr && size == call->virtual_unlock.size) - { - result->virtual_unlock.status = NtUnlockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 ); - result->virtual_unlock.addr = wine_server_client_ptr( addr ); - result->virtual_unlock.size = size; - } - else result->virtual_unlock.status = STATUS_INVALID_PARAMETER; - break; - case APC_MAP_VIEW: - result->type = call->type; - addr = wine_server_get_ptr( call->map_view.addr ); - size = call->map_view.size; - bits = call->map_view.zero_bits; - if ((ULONG_PTR)addr == call->map_view.addr && size == call->map_view.size && - bits == call->map_view.zero_bits) - { - LARGE_INTEGER offset; - offset.QuadPart = call->map_view.offset; - result->map_view.status = NtMapViewOfSection( wine_server_ptr_handle(call->map_view.handle), - NtCurrentProcess(), - &addr, bits, 0, &offset, &size, 0, - call->map_view.alloc_type, call->map_view.prot ); - result->map_view.addr = wine_server_client_ptr( addr ); - result->map_view.size = size; - } - else result->map_view.status = STATUS_INVALID_PARAMETER; - NtClose( wine_server_ptr_handle(call->map_view.handle) ); - break; - case APC_UNMAP_VIEW: - result->type = call->type; - addr = wine_server_get_ptr( call->unmap_view.addr ); - if ((ULONG_PTR)addr == call->unmap_view.addr) - result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr ); - else - result->unmap_view.status = STATUS_INVALID_PARAMETER; - break; - case APC_CREATE_THREAD: - { - CLIENT_ID id; - HANDLE handle; - SIZE_T reserve = call->create_thread.reserve; - SIZE_T commit = call->create_thread.commit; - void *func = wine_server_get_ptr( call->create_thread.func ); - void *arg = wine_server_get_ptr( call->create_thread.arg ); - - result->type = call->type; - if (reserve == call->create_thread.reserve && commit == call->create_thread.commit && - (ULONG_PTR)func == call->create_thread.func && (ULONG_PTR)arg == call->create_thread.arg) - { - result->create_thread.status = RtlCreateUserThread( NtCurrentProcess(), NULL, - call->create_thread.suspend, NULL, - reserve, commit, func, arg, &handle, &id ); - result->create_thread.handle = wine_server_obj_handle( handle ); - result->create_thread.tid = HandleToULong(id.UniqueThread); - } - else result->create_thread.status = STATUS_INVALID_PARAMETER; - break; - } - case APC_BREAK_PROCESS: - result->type = APC_BREAK_PROCESS; - result->break_process.status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0, - DbgUiRemoteBreakin, NULL, NULL, NULL ); - break; - default: - server_protocol_error( "get_apc_request: bad type %d\n", call->type ); - break; - } -} - - -/*********************************************************************** - * server_select - */ -unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags, - timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, user_apc_t *user_apc ) -{ - unsigned int ret; - int cookie; - obj_handle_t apc_handle = 0; - context_t server_context; - BOOL suspend_context = FALSE; - apc_call_t call; - apc_result_t result; - sigset_t old_set; - - memset( &result, 0, sizeof(result) ); - if (context) - { - suspend_context = TRUE; - context_to_server( &server_context, context ); - } - - do - { - pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); - for (;;) - { - SERVER_START_REQ( select ) - { - req->flags = flags; - req->cookie = wine_server_client_ptr( &cookie ); - req->prev_apc = apc_handle; - req->timeout = abs_timeout; - req->size = size; - wine_server_add_data( req, &result, sizeof(result) ); - wine_server_add_data( req, select_op, size ); - if (suspend_context) - { - wine_server_add_data( req, &server_context, sizeof(server_context) ); - suspend_context = FALSE; /* server owns the context now */ - } - if (context) wine_server_set_reply( req, &server_context, sizeof(server_context) ); - ret = unix_funcs->server_call_unlocked( req ); - apc_handle = reply->apc_handle; - call = reply->call; - if (wine_server_reply_size( reply )) - { - DWORD context_flags = context->ContextFlags; /* unchanged registers are still available */ - context_from_server( context, &server_context ); - context->ContextFlags |= context_flags; - } - } - SERVER_END_REQ; - - if (ret != STATUS_KERNEL_APC) break; - invoke_system_apc( &call, &result ); - - /* don't signal multiple times */ - if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) - size = offsetof( select_op_t, signal_and_wait.signal ); - } - pthread_sigmask( SIG_SETMASK, &old_set, NULL ); - if (cs) - { - RtlLeaveCriticalSection( cs ); - cs = NULL; - } - if (ret != STATUS_PENDING) break; - - ret = wait_select_reply( &cookie ); - } - while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC); - - if (ret == STATUS_USER_APC) *user_apc = call.user; - return ret; -} - - -/*********************************************************************** - * server_wait - */ -unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, - const LARGE_INTEGER *timeout ) -{ - timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; - BOOL user_apc = FALSE; - unsigned int ret; - user_apc_t apc; - - if (abs_timeout < 0) - { - LARGE_INTEGER now; - - RtlQueryPerformanceCounter(&now); - abs_timeout -= now.QuadPart; - } - - for (;;) - { - ret = server_select( select_op, size, flags, abs_timeout, NULL, NULL, &apc ); - if (ret != STATUS_USER_APC) break; - invoke_apc( &apc ); - - /* if we ran a user apc we have to check once more if additional apcs are queued, - * but we don't want to wait */ - abs_timeout = 0; - user_apc = TRUE; - size = 0; - /* don't signal multiple times */ - if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) - size = offsetof( select_op_t, signal_and_wait.signal ); - } - - if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC; - - /* A test on Windows 2000 shows that Windows always yields during - a wait, but a wait that is hit by an event gets a priority - boost as well. This seems to model that behavior the closest. */ - if (ret == STATUS_TIMEOUT) NtYieldExecution(); - - return ret; -} - - -/*********************************************************************** - * server_queue_process_apc - */ -unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) -{ - for (;;) - { - unsigned int ret; - HANDLE handle = 0; - BOOL self = FALSE; - - SERVER_START_REQ( queue_apc ) - { - req->handle = wine_server_obj_handle( process ); - req->call = *call; - if (!(ret = wine_server_call( req ))) - { - handle = wine_server_ptr_handle( reply->handle ); - self = reply->self; - } - } - SERVER_END_REQ; - if (ret != STATUS_SUCCESS) return ret; - - if (self) - { - invoke_system_apc( call, result ); - } - else - { - NtWaitForSingleObject( handle, FALSE, NULL ); - - SERVER_START_REQ( get_apc_result ) - { - req->handle = wine_server_obj_handle( handle ); - if (!(ret = wine_server_call( req ))) *result = reply->result; - } - SERVER_END_REQ; - - if (!ret && result->type == APC_NONE) continue; /* APC didn't run, try again */ - } - return ret; - } -} - - /*********************************************************************** * wine_server_send_fd (NTDLL.@) * diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index ad967d20e00..7aee9c1a02b 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -1101,7 +1101,7 @@ static NTSTATUS wait_objects( DWORD count, const HANDLE *handles, if (alertable) flags |= SELECT_ALERTABLE; select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL; for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] ); - return server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout ); + return unix_funcs->server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout ); } @@ -1140,7 +1140,7 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWa select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT; select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject ); select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject ); - return server_wait( &select_op, sizeof(select_op.signal_and_wait), flags, timeout ); + return unix_funcs->server_wait( &select_op, sizeof(select_op.signal_and_wait), flags, timeout ); } @@ -1165,7 +1165,7 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou { /* if alertable, we need to query the server */ if (alertable) - return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); + return unix_funcs->server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */ { @@ -1264,7 +1264,7 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT; select_op.keyed_event.handle = wine_server_obj_handle( handle ); select_op.keyed_event.key = wine_server_client_ptr( key ); - return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout ); + return unix_funcs->server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout ); } /****************************************************************************** @@ -1282,7 +1282,7 @@ NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key, select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE; select_op.keyed_event.handle = wine_server_obj_handle( handle ); select_op.keyed_event.key = wine_server_client_ptr( key ); - return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout ); + return unix_funcs->server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout ); } /****************************************************************** @@ -2579,7 +2579,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size select_op.keyed_event.handle = wine_server_obj_handle( keyed_event ); select_op.keyed_event.key = wine_server_client_ptr( addr ); - return server_select( &select_op, sizeof(select_op.keyed_event), SELECT_INTERRUPTIBLE, abs_timeout, NULL, &addr_section, NULL ); + return unix_funcs->server_select( &select_op, sizeof(select_op.keyed_event), SELECT_INTERRUPTIBLE, abs_timeout, NULL, &addr_section, NULL ); } /*********************************************************************** diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 785f3b99d47..bb11521cf69 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -413,7 +413,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr, call.create_thread.reserve = stack_reserve; call.create_thread.commit = stack_commit; call.create_thread.suspend = suspended; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.create_thread.status == STATUS_SUCCESS) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index eeaa685d516..aa020845bb9 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1010,6 +1010,9 @@ static struct unix_funcs unix_funcs = get_thread_ldt_entry, server_call_unlocked, wine_server_call, + server_select, + server_wait, + server_queue_process_apc, server_send_fd, server_get_unix_fd, server_fd_to_handle, diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index d5f2216fbdb..8889c5d4b12 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -334,6 +334,430 @@ void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sig } +/*********************************************************************** + * wait_select_reply + * + * Wait for a reply on the waiting pipe of the current thread. + */ +static int wait_select_reply( void *cookie ) +{ + int signaled; + struct wake_up_reply reply; + for (;;) + { + int ret; + ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) ); + if (ret == sizeof(reply)) + { + if (!reply.cookie) abort_thread( reply.signaled ); /* thread got killed */ + if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled; + /* we stole another reply, wait for the real one */ + signaled = wait_select_reply( cookie ); + /* and now put the wrong one back in the pipe */ + for (;;) + { + ret = write( ntdll_get_thread_data()->wait_fd[1], &reply, sizeof(reply) ); + if (ret == sizeof(reply)) break; + if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret ); + if (errno == EINTR) continue; + server_protocol_perror("wakeup write"); + } + return signaled; + } + if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret ); + if (errno == EINTR) continue; + server_protocol_perror("wakeup read"); + } +} + + +static void invoke_apc( const user_apc_t *apc ) +{ + switch( apc->type ) + { + case APC_USER: + { + void (WINAPI *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR) = wine_server_get_ptr( apc->user.func ); + func( apc->user.args[0], apc->user.args[1], apc->user.args[2] ); + break; + } + case APC_TIMER: + { + void (WINAPI *func)(void*, unsigned int, unsigned int) = wine_server_get_ptr( apc->user.func ); + func( wine_server_get_ptr( apc->user.args[1] ), + (DWORD)apc->timer.time, (DWORD)(apc->timer.time >> 32) ); + break; + } + default: + server_protocol_error( "get_apc_request: bad type %d\n", apc->type ); + break; + } +} + +/*********************************************************************** + * invoke_apc + * + * Invoke a single APC. + * + */ +static void invoke_system_apc( const apc_call_t *call, apc_result_t *result ) +{ + SIZE_T size, bits; + void *addr; + + memset( result, 0, sizeof(*result) ); + + switch (call->type) + { + case APC_NONE: + break; + case APC_ASYNC_IO: + { + IO_STATUS_BLOCK *iosb = wine_server_get_ptr( call->async_io.sb ); + NTSTATUS (**user)(void *, IO_STATUS_BLOCK *, NTSTATUS) = wine_server_get_ptr( call->async_io.user ); + result->type = call->type; + result->async_io.status = (*user)( user, iosb, call->async_io.status ); + if (result->async_io.status != STATUS_PENDING) + result->async_io.total = iosb->Information; + break; + } + case APC_VIRTUAL_ALLOC: + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_alloc.addr ); + size = call->virtual_alloc.size; + bits = call->virtual_alloc.zero_bits; + if ((ULONG_PTR)addr == call->virtual_alloc.addr && size == call->virtual_alloc.size && + bits == call->virtual_alloc.zero_bits) + { + result->virtual_alloc.status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, bits, &size, + call->virtual_alloc.op_type, + call->virtual_alloc.prot ); + result->virtual_alloc.addr = wine_server_client_ptr( addr ); + result->virtual_alloc.size = size; + } + else result->virtual_alloc.status = STATUS_WORKING_SET_LIMIT_RANGE; + break; + case APC_VIRTUAL_FREE: + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_free.addr ); + size = call->virtual_free.size; + if ((ULONG_PTR)addr == call->virtual_free.addr && size == call->virtual_free.size) + { + result->virtual_free.status = NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, + call->virtual_free.op_type ); + result->virtual_free.addr = wine_server_client_ptr( addr ); + result->virtual_free.size = size; + } + else result->virtual_free.status = STATUS_INVALID_PARAMETER; + break; + case APC_VIRTUAL_QUERY: + { + MEMORY_BASIC_INFORMATION info; + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_query.addr ); + if ((ULONG_PTR)addr == call->virtual_query.addr) + result->virtual_query.status = NtQueryVirtualMemory( NtCurrentProcess(), + addr, MemoryBasicInformation, &info, + sizeof(info), NULL ); + else + result->virtual_query.status = STATUS_WORKING_SET_LIMIT_RANGE; + + if (result->virtual_query.status == STATUS_SUCCESS) + { + result->virtual_query.base = wine_server_client_ptr( info.BaseAddress ); + result->virtual_query.alloc_base = wine_server_client_ptr( info.AllocationBase ); + result->virtual_query.size = info.RegionSize; + result->virtual_query.prot = info.Protect; + result->virtual_query.alloc_prot = info.AllocationProtect; + result->virtual_query.state = info.State >> 12; + result->virtual_query.alloc_type = info.Type >> 16; + } + break; + } + case APC_VIRTUAL_PROTECT: + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_protect.addr ); + size = call->virtual_protect.size; + if ((ULONG_PTR)addr == call->virtual_protect.addr && size == call->virtual_protect.size) + { + result->virtual_protect.status = NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, + call->virtual_protect.prot, + &result->virtual_protect.prot ); + result->virtual_protect.addr = wine_server_client_ptr( addr ); + result->virtual_protect.size = size; + } + else result->virtual_protect.status = STATUS_INVALID_PARAMETER; + break; + case APC_VIRTUAL_FLUSH: + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_flush.addr ); + size = call->virtual_flush.size; + if ((ULONG_PTR)addr == call->virtual_flush.addr && size == call->virtual_flush.size) + { + result->virtual_flush.status = NtFlushVirtualMemory( NtCurrentProcess(), + (const void **)&addr, &size, 0 ); + result->virtual_flush.addr = wine_server_client_ptr( addr ); + result->virtual_flush.size = size; + } + else result->virtual_flush.status = STATUS_INVALID_PARAMETER; + break; + case APC_VIRTUAL_LOCK: + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_lock.addr ); + size = call->virtual_lock.size; + if ((ULONG_PTR)addr == call->virtual_lock.addr && size == call->virtual_lock.size) + { + result->virtual_lock.status = NtLockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 ); + result->virtual_lock.addr = wine_server_client_ptr( addr ); + result->virtual_lock.size = size; + } + else result->virtual_lock.status = STATUS_INVALID_PARAMETER; + break; + case APC_VIRTUAL_UNLOCK: + result->type = call->type; + addr = wine_server_get_ptr( call->virtual_unlock.addr ); + size = call->virtual_unlock.size; + if ((ULONG_PTR)addr == call->virtual_unlock.addr && size == call->virtual_unlock.size) + { + result->virtual_unlock.status = NtUnlockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 ); + result->virtual_unlock.addr = wine_server_client_ptr( addr ); + result->virtual_unlock.size = size; + } + else result->virtual_unlock.status = STATUS_INVALID_PARAMETER; + break; + case APC_MAP_VIEW: + result->type = call->type; + addr = wine_server_get_ptr( call->map_view.addr ); + size = call->map_view.size; + bits = call->map_view.zero_bits; + if ((ULONG_PTR)addr == call->map_view.addr && size == call->map_view.size && + bits == call->map_view.zero_bits) + { + LARGE_INTEGER offset; + offset.QuadPart = call->map_view.offset; + result->map_view.status = NtMapViewOfSection( wine_server_ptr_handle(call->map_view.handle), + NtCurrentProcess(), + &addr, bits, 0, &offset, &size, 0, + call->map_view.alloc_type, call->map_view.prot ); + result->map_view.addr = wine_server_client_ptr( addr ); + result->map_view.size = size; + } + else result->map_view.status = STATUS_INVALID_PARAMETER; + NtClose( wine_server_ptr_handle(call->map_view.handle) ); + break; + case APC_UNMAP_VIEW: + result->type = call->type; + addr = wine_server_get_ptr( call->unmap_view.addr ); + if ((ULONG_PTR)addr == call->unmap_view.addr) + result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr ); + else + result->unmap_view.status = STATUS_INVALID_PARAMETER; + break; + case APC_CREATE_THREAD: + { + CLIENT_ID id; + HANDLE handle; + SIZE_T reserve = call->create_thread.reserve; + SIZE_T commit = call->create_thread.commit; + void *func = wine_server_get_ptr( call->create_thread.func ); + void *arg = wine_server_get_ptr( call->create_thread.arg ); + + result->type = call->type; + if (reserve == call->create_thread.reserve && commit == call->create_thread.commit && + (ULONG_PTR)func == call->create_thread.func && (ULONG_PTR)arg == call->create_thread.arg) + { + result->create_thread.status = RtlCreateUserThread( NtCurrentProcess(), NULL, + call->create_thread.suspend, NULL, + reserve, commit, func, arg, &handle, &id ); + result->create_thread.handle = wine_server_obj_handle( handle ); + result->create_thread.tid = HandleToULong(id.UniqueThread); + } + else result->create_thread.status = STATUS_INVALID_PARAMETER; + break; + } + case APC_BREAK_PROCESS: + result->type = APC_BREAK_PROCESS; + result->break_process.status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0, + DbgUiRemoteBreakin, NULL, NULL, NULL ); + break; + default: + server_protocol_error( "get_apc_request: bad type %d\n", call->type ); + break; + } +} + + +/*********************************************************************** + * server_select + */ +unsigned int CDECL server_select( const select_op_t *select_op, data_size_t size, UINT flags, + timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, + user_apc_t *user_apc ) +{ + unsigned int ret; + int cookie; + obj_handle_t apc_handle = 0; + context_t server_context; + BOOL suspend_context = FALSE; + apc_call_t call; + apc_result_t result; + sigset_t old_set; + + memset( &result, 0, sizeof(result) ); + if (context) + { + suspend_context = TRUE; + context_to_server( &server_context, context ); + } + + do + { + pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); + for (;;) + { + SERVER_START_REQ( select ) + { + req->flags = flags; + req->cookie = wine_server_client_ptr( &cookie ); + req->prev_apc = apc_handle; + req->timeout = abs_timeout; + req->size = size; + wine_server_add_data( req, &result, sizeof(result) ); + wine_server_add_data( req, select_op, size ); + if (suspend_context) + { + wine_server_add_data( req, &server_context, sizeof(server_context) ); + suspend_context = FALSE; /* server owns the context now */ + } + if (context) wine_server_set_reply( req, &server_context, sizeof(server_context) ); + ret = server_call_unlocked( req ); + apc_handle = reply->apc_handle; + call = reply->call; + if (wine_server_reply_size( reply )) + { + DWORD context_flags = context->ContextFlags; /* unchanged registers are still available */ + context_from_server( context, &server_context ); + context->ContextFlags |= context_flags; + } + } + SERVER_END_REQ; + + if (ret != STATUS_KERNEL_APC) break; + invoke_system_apc( &call, &result ); + + /* don't signal multiple times */ + if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) + size = offsetof( select_op_t, signal_and_wait.signal ); + } + pthread_sigmask( SIG_SETMASK, &old_set, NULL ); + if (cs) + { + RtlLeaveCriticalSection( cs ); + cs = NULL; + } + if (ret != STATUS_PENDING) break; + + ret = wait_select_reply( &cookie ); + } + while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC); + + if (ret == STATUS_USER_APC) *user_apc = call.user; + return ret; +} + + +/*********************************************************************** + * server_wait + */ +unsigned int CDECL server_wait( const select_op_t *select_op, data_size_t size, UINT flags, + const LARGE_INTEGER *timeout ) +{ + timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; + BOOL user_apc = FALSE; + unsigned int ret; + user_apc_t apc; + + if (abs_timeout < 0) + { + LARGE_INTEGER now; + + RtlQueryPerformanceCounter(&now); + abs_timeout -= now.QuadPart; + } + + for (;;) + { + ret = server_select( select_op, size, flags, abs_timeout, NULL, NULL, &apc ); + if (ret != STATUS_USER_APC) break; + invoke_apc( &apc ); + + /* if we ran a user apc we have to check once more if additional apcs are queued, + * but we don't want to wait */ + abs_timeout = 0; + user_apc = TRUE; + size = 0; + /* don't signal multiple times */ + if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) + size = offsetof( select_op_t, signal_and_wait.signal ); + } + + if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC; + + /* A test on Windows 2000 shows that Windows always yields during + a wait, but a wait that is hit by an event gets a priority + boost as well. This seems to model that behavior the closest. */ + if (ret == STATUS_TIMEOUT) NtYieldExecution(); + + return ret; +} + + +/*********************************************************************** + * server_queue_process_apc + */ +unsigned int CDECL server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) +{ + for (;;) + { + unsigned int ret; + HANDLE handle = 0; + BOOL self = FALSE; + + SERVER_START_REQ( queue_apc ) + { + req->handle = wine_server_obj_handle( process ); + req->call = *call; + if (!(ret = wine_server_call( req ))) + { + handle = wine_server_ptr_handle( reply->handle ); + self = reply->self; + } + } + SERVER_END_REQ; + if (ret != STATUS_SUCCESS) return ret; + + if (self) + { + invoke_system_apc( call, result ); + } + else + { + NtWaitForSingleObject( handle, FALSE, NULL ); + + SERVER_START_REQ( get_apc_result ) + { + req->handle = wine_server_obj_handle( handle ); + if (!(ret = wine_server_call( req ))) *result = reply->result; + } + SERVER_END_REQ; + + if (!ret && result->type == APC_NONE) continue; /* APC didn't run, try again */ + } + return ret; + } +} + + /*********************************************************************** * server_send_fd * diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index de15851781b..0988eda350f 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -69,6 +69,116 @@ static pthread_key_t teb_key; +/*********************************************************************** + * context_to_server + * + * Convert a register context to the server format. + */ +NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) +{ + DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_ARM; + + if (flags & CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->ctl.arm_regs.sp = from->Sp; + to->ctl.arm_regs.lr = from->Lr; + to->ctl.arm_regs.pc = from->Pc; + to->ctl.arm_regs.cpsr = from->Cpsr; + } + if (flags & CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + to->integer.arm_regs.r[0] = from->R0; + to->integer.arm_regs.r[1] = from->R1; + to->integer.arm_regs.r[2] = from->R2; + to->integer.arm_regs.r[3] = from->R3; + to->integer.arm_regs.r[4] = from->R4; + to->integer.arm_regs.r[5] = from->R5; + to->integer.arm_regs.r[6] = from->R6; + to->integer.arm_regs.r[7] = from->R7; + to->integer.arm_regs.r[8] = from->R8; + to->integer.arm_regs.r[9] = from->R9; + to->integer.arm_regs.r[10] = from->R10; + to->integer.arm_regs.r[11] = from->R11; + to->integer.arm_regs.r[12] = from->R12; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i]; + to->fp.arm_regs.fpscr = from->Fpscr; + } + if (flags & CONTEXT_DEBUG_REGISTERS) + { + to->flags |= SERVER_CTX_DEBUG_REGISTERS; + for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i]; + for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i]; + for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i]; + for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i]; + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * context_from_server + * + * Convert a register context from the server format. + */ +NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) +{ + DWORD i; + + if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = CONTEXT_ARM; + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= CONTEXT_CONTROL; + to->Sp = from->ctl.arm_regs.sp; + to->Lr = from->ctl.arm_regs.lr; + to->Pc = from->ctl.arm_regs.pc; + to->Cpsr = from->ctl.arm_regs.cpsr; + } + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= CONTEXT_INTEGER; + to->R0 = from->integer.arm_regs.r[0]; + to->R1 = from->integer.arm_regs.r[1]; + to->R2 = from->integer.arm_regs.r[2]; + to->R3 = from->integer.arm_regs.r[3]; + to->R4 = from->integer.arm_regs.r[4]; + to->R5 = from->integer.arm_regs.r[5]; + to->R6 = from->integer.arm_regs.r[6]; + to->R7 = from->integer.arm_regs.r[7]; + to->R8 = from->integer.arm_regs.r[8]; + to->R9 = from->integer.arm_regs.r[9]; + to->R10 = from->integer.arm_regs.r[10]; + to->R11 = from->integer.arm_regs.r[11]; + to->R12 = from->integer.arm_regs.r[12]; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= CONTEXT_FLOATING_POINT; + for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i]; + to->Fpscr = from->fp.arm_regs.fpscr; + } + if (from->flags & SERVER_CTX_DEBUG_REGISTERS) + { + to->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i]; + for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i]; + for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i]; + for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i]; + } + return STATUS_SUCCESS; +} + + /********************************************************************** * get_thread_ldt_entry */ diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 0e69d77217a..6a407c63d98 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -74,6 +74,104 @@ static pthread_key_t teb_key; static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */ +/*********************************************************************** + * context_to_server + * + * Convert a register context to the server format. + */ +NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) +{ + DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM64; /* get rid of CPU id */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_ARM64; + + if (flags & CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->integer.arm64_regs.x[29] = from->u.s.Fp; + to->integer.arm64_regs.x[30] = from->u.s.Lr; + to->ctl.arm64_regs.sp = from->Sp; + to->ctl.arm64_regs.pc = from->Pc; + to->ctl.arm64_regs.pstate = from->Cpsr; + } + if (flags & CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->u.X[i]; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + for (i = 0; i < 32; i++) + { + to->fp.arm64_regs.q[i].low = from->V[i].s.Low; + to->fp.arm64_regs.q[i].high = from->V[i].s.High; + } + to->fp.arm64_regs.fpcr = from->Fpcr; + to->fp.arm64_regs.fpsr = from->Fpsr; + } + if (flags & CONTEXT_DEBUG_REGISTERS) + { + to->flags |= SERVER_CTX_DEBUG_REGISTERS; + for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i]; + for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i]; + for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i]; + for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i]; + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * context_from_server + * + * Convert a register context from the server format. + */ +NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) +{ + DWORD i; + + if (from->cpu != CPU_ARM64) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = CONTEXT_ARM64; + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= CONTEXT_CONTROL; + to->u.s.Fp = from->integer.arm64_regs.x[29]; + to->u.s.Lr = from->integer.arm64_regs.x[30]; + to->Sp = from->ctl.arm64_regs.sp; + to->Pc = from->ctl.arm64_regs.pc; + to->Cpsr = from->ctl.arm64_regs.pstate; + } + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= CONTEXT_INTEGER; + for (i = 0; i <= 28; i++) to->u.X[i] = from->integer.arm64_regs.x[i]; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= CONTEXT_FLOATING_POINT; + for (i = 0; i < 32; i++) + { + to->V[i].s.Low = from->fp.arm64_regs.q[i].low; + to->V[i].s.High = from->fp.arm64_regs.q[i].high; + } + to->Fpcr = from->fp.arm64_regs.fpcr; + to->Fpsr = from->fp.arm64_regs.fpsr; + } + if (from->flags & SERVER_CTX_DEBUG_REGISTERS) + { + to->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i]; + for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i]; + for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i]; + for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i]; + } + return STATUS_SUCCESS; +} + + /********************************************************************** * get_thread_ldt_entry */ diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 9e56c99e547..320ffa68407 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -168,6 +168,148 @@ static inline int is_gdt_sel( WORD sel ) } +/*********************************************************************** + * context_to_server + * + * Convert a register context to the server format. + */ +NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) +{ + DWORD flags = from->ContextFlags & ~CONTEXT_i386; /* get rid of CPU id */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_x86; + + if (flags & CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->ctl.i386_regs.ebp = from->Ebp; + to->ctl.i386_regs.esp = from->Esp; + to->ctl.i386_regs.eip = from->Eip; + to->ctl.i386_regs.cs = from->SegCs; + to->ctl.i386_regs.ss = from->SegSs; + to->ctl.i386_regs.eflags = from->EFlags; + } + if (flags & CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + to->integer.i386_regs.eax = from->Eax; + to->integer.i386_regs.ebx = from->Ebx; + to->integer.i386_regs.ecx = from->Ecx; + to->integer.i386_regs.edx = from->Edx; + to->integer.i386_regs.esi = from->Esi; + to->integer.i386_regs.edi = from->Edi; + } + if (flags & CONTEXT_SEGMENTS) + { + to->flags |= SERVER_CTX_SEGMENTS; + to->seg.i386_regs.ds = from->SegDs; + to->seg.i386_regs.es = from->SegEs; + to->seg.i386_regs.fs = from->SegFs; + to->seg.i386_regs.gs = from->SegGs; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + to->fp.i386_regs.ctrl = from->FloatSave.ControlWord; + to->fp.i386_regs.status = from->FloatSave.StatusWord; + to->fp.i386_regs.tag = from->FloatSave.TagWord; + to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset; + to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector; + to->fp.i386_regs.data_off = from->FloatSave.DataOffset; + to->fp.i386_regs.data_sel = from->FloatSave.DataSelector; + to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState; + memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) ); + } + if (flags & CONTEXT_DEBUG_REGISTERS) + { + to->flags |= SERVER_CTX_DEBUG_REGISTERS; + to->debug.i386_regs.dr0 = from->Dr0; + to->debug.i386_regs.dr1 = from->Dr1; + to->debug.i386_regs.dr2 = from->Dr2; + to->debug.i386_regs.dr3 = from->Dr3; + to->debug.i386_regs.dr6 = from->Dr6; + to->debug.i386_regs.dr7 = from->Dr7; + } + if (flags & CONTEXT_EXTENDED_REGISTERS) + { + to->flags |= SERVER_CTX_EXTENDED_REGISTERS; + memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) ); + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * context_from_server + * + * Convert a register context from the server format. + */ +NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) +{ + if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = CONTEXT_i386; + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= CONTEXT_CONTROL; + to->Ebp = from->ctl.i386_regs.ebp; + to->Esp = from->ctl.i386_regs.esp; + to->Eip = from->ctl.i386_regs.eip; + to->SegCs = from->ctl.i386_regs.cs; + to->SegSs = from->ctl.i386_regs.ss; + to->EFlags = from->ctl.i386_regs.eflags; + } + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= CONTEXT_INTEGER; + to->Eax = from->integer.i386_regs.eax; + to->Ebx = from->integer.i386_regs.ebx; + to->Ecx = from->integer.i386_regs.ecx; + to->Edx = from->integer.i386_regs.edx; + to->Esi = from->integer.i386_regs.esi; + to->Edi = from->integer.i386_regs.edi; + } + if (from->flags & SERVER_CTX_SEGMENTS) + { + to->ContextFlags |= CONTEXT_SEGMENTS; + to->SegDs = from->seg.i386_regs.ds; + to->SegEs = from->seg.i386_regs.es; + to->SegFs = from->seg.i386_regs.fs; + to->SegGs = from->seg.i386_regs.gs; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= CONTEXT_FLOATING_POINT; + to->FloatSave.ControlWord = from->fp.i386_regs.ctrl; + to->FloatSave.StatusWord = from->fp.i386_regs.status; + to->FloatSave.TagWord = from->fp.i386_regs.tag; + to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off; + to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel; + to->FloatSave.DataOffset = from->fp.i386_regs.data_off; + to->FloatSave.DataSelector = from->fp.i386_regs.data_sel; + to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx; + memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) ); + } + if (from->flags & SERVER_CTX_DEBUG_REGISTERS) + { + to->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + to->Dr0 = from->debug.i386_regs.dr0; + to->Dr1 = from->debug.i386_regs.dr1; + to->Dr2 = from->debug.i386_regs.dr2; + to->Dr3 = from->debug.i386_regs.dr3; + to->Dr6 = from->debug.i386_regs.dr6; + to->Dr7 = from->debug.i386_regs.dr7; + } + if (from->flags & SERVER_CTX_EXTENDED_REGISTERS) + { + to->ContextFlags |= CONTEXT_EXTENDED_REGISTERS; + memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) ); + } + return STATUS_SUCCESS; +} + + /*********************************************************************** * LDT support */ diff --git a/dlls/ntdll/unix/signal_powerpc.c b/dlls/ntdll/unix/signal_powerpc.c index 246db2dcbd4..9dd7eaecc79 100644 --- a/dlls/ntdll/unix/signal_powerpc.c +++ b/dlls/ntdll/unix/signal_powerpc.c @@ -66,6 +66,208 @@ static pthread_key_t teb_key; +/*********************************************************************** + * context_to_server + * + * Convert a register context to the server format. + */ +NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) +{ + DWORD flags = from->ContextFlags; /* no CPU id? */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_POWERPC; + + if (flags & CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->ctl.powerpc_regs.iar = from->Iar; + to->ctl.powerpc_regs.msr = from->Msr; + to->ctl.powerpc_regs.ctr = from->Ctr; + to->ctl.powerpc_regs.lr = from->Lr; + to->ctl.powerpc_regs.dar = from->Dar; + to->ctl.powerpc_regs.dsisr = from->Dsisr; + to->ctl.powerpc_regs.trap = from->Trap; + } + if (flags & CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + to->integer.powerpc_regs.gpr[0] = from->Gpr0; + to->integer.powerpc_regs.gpr[1] = from->Gpr1; + to->integer.powerpc_regs.gpr[2] = from->Gpr2; + to->integer.powerpc_regs.gpr[3] = from->Gpr3; + to->integer.powerpc_regs.gpr[4] = from->Gpr4; + to->integer.powerpc_regs.gpr[5] = from->Gpr5; + to->integer.powerpc_regs.gpr[6] = from->Gpr6; + to->integer.powerpc_regs.gpr[7] = from->Gpr7; + to->integer.powerpc_regs.gpr[8] = from->Gpr8; + to->integer.powerpc_regs.gpr[9] = from->Gpr9; + to->integer.powerpc_regs.gpr[10] = from->Gpr10; + to->integer.powerpc_regs.gpr[11] = from->Gpr11; + to->integer.powerpc_regs.gpr[12] = from->Gpr12; + to->integer.powerpc_regs.gpr[13] = from->Gpr13; + to->integer.powerpc_regs.gpr[14] = from->Gpr14; + to->integer.powerpc_regs.gpr[15] = from->Gpr15; + to->integer.powerpc_regs.gpr[16] = from->Gpr16; + to->integer.powerpc_regs.gpr[17] = from->Gpr17; + to->integer.powerpc_regs.gpr[18] = from->Gpr18; + to->integer.powerpc_regs.gpr[19] = from->Gpr19; + to->integer.powerpc_regs.gpr[20] = from->Gpr20; + to->integer.powerpc_regs.gpr[21] = from->Gpr21; + to->integer.powerpc_regs.gpr[22] = from->Gpr22; + to->integer.powerpc_regs.gpr[23] = from->Gpr23; + to->integer.powerpc_regs.gpr[24] = from->Gpr24; + to->integer.powerpc_regs.gpr[25] = from->Gpr25; + to->integer.powerpc_regs.gpr[26] = from->Gpr26; + to->integer.powerpc_regs.gpr[27] = from->Gpr27; + to->integer.powerpc_regs.gpr[28] = from->Gpr28; + to->integer.powerpc_regs.gpr[29] = from->Gpr29; + to->integer.powerpc_regs.gpr[30] = from->Gpr30; + to->integer.powerpc_regs.gpr[31] = from->Gpr31; + to->integer.powerpc_regs.xer = from->Xer; + to->integer.powerpc_regs.cr = from->Cr; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + to->fp.powerpc_regs.fpr[0] = from->Fpr0; + to->fp.powerpc_regs.fpr[1] = from->Fpr1; + to->fp.powerpc_regs.fpr[2] = from->Fpr2; + to->fp.powerpc_regs.fpr[3] = from->Fpr3; + to->fp.powerpc_regs.fpr[4] = from->Fpr4; + to->fp.powerpc_regs.fpr[5] = from->Fpr5; + to->fp.powerpc_regs.fpr[6] = from->Fpr6; + to->fp.powerpc_regs.fpr[7] = from->Fpr7; + to->fp.powerpc_regs.fpr[8] = from->Fpr8; + to->fp.powerpc_regs.fpr[9] = from->Fpr9; + to->fp.powerpc_regs.fpr[10] = from->Fpr10; + to->fp.powerpc_regs.fpr[11] = from->Fpr11; + to->fp.powerpc_regs.fpr[12] = from->Fpr12; + to->fp.powerpc_regs.fpr[13] = from->Fpr13; + to->fp.powerpc_regs.fpr[14] = from->Fpr14; + to->fp.powerpc_regs.fpr[15] = from->Fpr15; + to->fp.powerpc_regs.fpr[16] = from->Fpr16; + to->fp.powerpc_regs.fpr[17] = from->Fpr17; + to->fp.powerpc_regs.fpr[18] = from->Fpr18; + to->fp.powerpc_regs.fpr[19] = from->Fpr19; + to->fp.powerpc_regs.fpr[20] = from->Fpr20; + to->fp.powerpc_regs.fpr[21] = from->Fpr21; + to->fp.powerpc_regs.fpr[22] = from->Fpr22; + to->fp.powerpc_regs.fpr[23] = from->Fpr23; + to->fp.powerpc_regs.fpr[24] = from->Fpr24; + to->fp.powerpc_regs.fpr[25] = from->Fpr25; + to->fp.powerpc_regs.fpr[26] = from->Fpr26; + to->fp.powerpc_regs.fpr[27] = from->Fpr27; + to->fp.powerpc_regs.fpr[28] = from->Fpr28; + to->fp.powerpc_regs.fpr[29] = from->Fpr29; + to->fp.powerpc_regs.fpr[30] = from->Fpr30; + to->fp.powerpc_regs.fpr[31] = from->Fpr31; + to->fp.powerpc_regs.fpscr = from->Fpscr; + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * context_from_server + * + * Convert a register context from the server format. + */ +NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) +{ + if (from->cpu != CPU_POWERPC) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = 0; /* no CPU id? */ + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= CONTEXT_CONTROL; + to->Msr = from->ctl.powerpc_regs.msr; + to->Ctr = from->ctl.powerpc_regs.ctr; + to->Iar = from->ctl.powerpc_regs.iar; + to->Lr = from->ctl.powerpc_regs.lr; + to->Dar = from->ctl.powerpc_regs.dar; + to->Dsisr = from->ctl.powerpc_regs.dsisr; + to->Trap = from->ctl.powerpc_regs.trap; + } + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= CONTEXT_INTEGER; + to->Gpr0 = from->integer.powerpc_regs.gpr[0]; + to->Gpr1 = from->integer.powerpc_regs.gpr[1]; + to->Gpr2 = from->integer.powerpc_regs.gpr[2]; + to->Gpr3 = from->integer.powerpc_regs.gpr[3]; + to->Gpr4 = from->integer.powerpc_regs.gpr[4]; + to->Gpr5 = from->integer.powerpc_regs.gpr[5]; + to->Gpr6 = from->integer.powerpc_regs.gpr[6]; + to->Gpr7 = from->integer.powerpc_regs.gpr[7]; + to->Gpr8 = from->integer.powerpc_regs.gpr[8]; + to->Gpr9 = from->integer.powerpc_regs.gpr[9]; + to->Gpr10 = from->integer.powerpc_regs.gpr[10]; + to->Gpr11 = from->integer.powerpc_regs.gpr[11]; + to->Gpr12 = from->integer.powerpc_regs.gpr[12]; + to->Gpr13 = from->integer.powerpc_regs.gpr[13]; + to->Gpr14 = from->integer.powerpc_regs.gpr[14]; + to->Gpr15 = from->integer.powerpc_regs.gpr[15]; + to->Gpr16 = from->integer.powerpc_regs.gpr[16]; + to->Gpr17 = from->integer.powerpc_regs.gpr[17]; + to->Gpr18 = from->integer.powerpc_regs.gpr[18]; + to->Gpr19 = from->integer.powerpc_regs.gpr[19]; + to->Gpr20 = from->integer.powerpc_regs.gpr[20]; + to->Gpr21 = from->integer.powerpc_regs.gpr[21]; + to->Gpr22 = from->integer.powerpc_regs.gpr[22]; + to->Gpr23 = from->integer.powerpc_regs.gpr[23]; + to->Gpr24 = from->integer.powerpc_regs.gpr[24]; + to->Gpr25 = from->integer.powerpc_regs.gpr[25]; + to->Gpr26 = from->integer.powerpc_regs.gpr[26]; + to->Gpr27 = from->integer.powerpc_regs.gpr[27]; + to->Gpr28 = from->integer.powerpc_regs.gpr[28]; + to->Gpr29 = from->integer.powerpc_regs.gpr[29]; + to->Gpr30 = from->integer.powerpc_regs.gpr[30]; + to->Gpr31 = from->integer.powerpc_regs.gpr[31]; + to->Xer = from->integer.powerpc_regs.xer; + to->Cr = from->integer.powerpc_regs.cr; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= CONTEXT_FLOATING_POINT; + to->Fpr0 = from->fp.powerpc_regs.fpr[0]; + to->Fpr1 = from->fp.powerpc_regs.fpr[1]; + to->Fpr2 = from->fp.powerpc_regs.fpr[2]; + to->Fpr3 = from->fp.powerpc_regs.fpr[3]; + to->Fpr4 = from->fp.powerpc_regs.fpr[4]; + to->Fpr5 = from->fp.powerpc_regs.fpr[5]; + to->Fpr6 = from->fp.powerpc_regs.fpr[6]; + to->Fpr7 = from->fp.powerpc_regs.fpr[7]; + to->Fpr8 = from->fp.powerpc_regs.fpr[8]; + to->Fpr9 = from->fp.powerpc_regs.fpr[9]; + to->Fpr10 = from->fp.powerpc_regs.fpr[10]; + to->Fpr11 = from->fp.powerpc_regs.fpr[11]; + to->Fpr12 = from->fp.powerpc_regs.fpr[12]; + to->Fpr13 = from->fp.powerpc_regs.fpr[13]; + to->Fpr14 = from->fp.powerpc_regs.fpr[14]; + to->Fpr15 = from->fp.powerpc_regs.fpr[15]; + to->Fpr16 = from->fp.powerpc_regs.fpr[16]; + to->Fpr17 = from->fp.powerpc_regs.fpr[17]; + to->Fpr18 = from->fp.powerpc_regs.fpr[18]; + to->Fpr19 = from->fp.powerpc_regs.fpr[19]; + to->Fpr20 = from->fp.powerpc_regs.fpr[20]; + to->Fpr21 = from->fp.powerpc_regs.fpr[21]; + to->Fpr22 = from->fp.powerpc_regs.fpr[22]; + to->Fpr23 = from->fp.powerpc_regs.fpr[23]; + to->Fpr24 = from->fp.powerpc_regs.fpr[24]; + to->Fpr25 = from->fp.powerpc_regs.fpr[25]; + to->Fpr26 = from->fp.powerpc_regs.fpr[26]; + to->Fpr27 = from->fp.powerpc_regs.fpr[27]; + to->Fpr28 = from->fp.powerpc_regs.fpr[28]; + to->Fpr29 = from->fp.powerpc_regs.fpr[29]; + to->Fpr30 = from->fp.powerpc_regs.fpr[30]; + to->Fpr31 = from->fp.powerpc_regs.fpr[31]; + to->Fpscr = from->fp.powerpc_regs.fpscr; + } + return STATUS_SUCCESS; +} + + /********************************************************************** * get_thread_ldt_entry */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index cc3dcd6db3c..a55f4f0b8f8 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -113,6 +113,140 @@ enum i386_trap_code static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */ +/*********************************************************************** + * context_to_server + * + * Convert a register context to the server format. + */ +NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) +{ + DWORD flags = from->ContextFlags & ~CONTEXT_AMD64; /* get rid of CPU id */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_x86_64; + + if (flags & CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->ctl.x86_64_regs.rbp = from->Rbp; + to->ctl.x86_64_regs.rip = from->Rip; + to->ctl.x86_64_regs.rsp = from->Rsp; + to->ctl.x86_64_regs.cs = from->SegCs; + to->ctl.x86_64_regs.ss = from->SegSs; + to->ctl.x86_64_regs.flags = from->EFlags; + } + if (flags & CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + to->integer.x86_64_regs.rax = from->Rax; + to->integer.x86_64_regs.rcx = from->Rcx; + to->integer.x86_64_regs.rdx = from->Rdx; + to->integer.x86_64_regs.rbx = from->Rbx; + to->integer.x86_64_regs.rsi = from->Rsi; + to->integer.x86_64_regs.rdi = from->Rdi; + to->integer.x86_64_regs.r8 = from->R8; + to->integer.x86_64_regs.r9 = from->R9; + to->integer.x86_64_regs.r10 = from->R10; + to->integer.x86_64_regs.r11 = from->R11; + to->integer.x86_64_regs.r12 = from->R12; + to->integer.x86_64_regs.r13 = from->R13; + to->integer.x86_64_regs.r14 = from->R14; + to->integer.x86_64_regs.r15 = from->R15; + } + if (flags & CONTEXT_SEGMENTS) + { + to->flags |= SERVER_CTX_SEGMENTS; + to->seg.x86_64_regs.ds = from->SegDs; + to->seg.x86_64_regs.es = from->SegEs; + to->seg.x86_64_regs.fs = from->SegFs; + to->seg.x86_64_regs.gs = from->SegGs; + } + if (flags & CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) ); + } + if (flags & CONTEXT_DEBUG_REGISTERS) + { + to->flags |= SERVER_CTX_DEBUG_REGISTERS; + to->debug.x86_64_regs.dr0 = from->Dr0; + to->debug.x86_64_regs.dr1 = from->Dr1; + to->debug.x86_64_regs.dr2 = from->Dr2; + to->debug.x86_64_regs.dr3 = from->Dr3; + to->debug.x86_64_regs.dr6 = from->Dr6; + to->debug.x86_64_regs.dr7 = from->Dr7; + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * context_from_server + * + * Convert a register context from the server format. + */ +NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) +{ + if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER; + + to->ContextFlags = CONTEXT_AMD64; + if (from->flags & SERVER_CTX_CONTROL) + { + to->ContextFlags |= CONTEXT_CONTROL; + to->Rbp = from->ctl.x86_64_regs.rbp; + to->Rip = from->ctl.x86_64_regs.rip; + to->Rsp = from->ctl.x86_64_regs.rsp; + to->SegCs = from->ctl.x86_64_regs.cs; + to->SegSs = from->ctl.x86_64_regs.ss; + to->EFlags = from->ctl.x86_64_regs.flags; + } + + if (from->flags & SERVER_CTX_INTEGER) + { + to->ContextFlags |= CONTEXT_INTEGER; + to->Rax = from->integer.x86_64_regs.rax; + to->Rcx = from->integer.x86_64_regs.rcx; + to->Rdx = from->integer.x86_64_regs.rdx; + to->Rbx = from->integer.x86_64_regs.rbx; + to->Rsi = from->integer.x86_64_regs.rsi; + to->Rdi = from->integer.x86_64_regs.rdi; + to->R8 = from->integer.x86_64_regs.r8; + to->R9 = from->integer.x86_64_regs.r9; + to->R10 = from->integer.x86_64_regs.r10; + to->R11 = from->integer.x86_64_regs.r11; + to->R12 = from->integer.x86_64_regs.r12; + to->R13 = from->integer.x86_64_regs.r13; + to->R14 = from->integer.x86_64_regs.r14; + to->R15 = from->integer.x86_64_regs.r15; + } + if (from->flags & SERVER_CTX_SEGMENTS) + { + to->ContextFlags |= CONTEXT_SEGMENTS; + to->SegDs = from->seg.x86_64_regs.ds; + to->SegEs = from->seg.x86_64_regs.es; + to->SegFs = from->seg.x86_64_regs.fs; + to->SegGs = from->seg.x86_64_regs.gs; + } + if (from->flags & SERVER_CTX_FLOATING_POINT) + { + to->ContextFlags |= CONTEXT_FLOATING_POINT; + memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) ); + to->MxCsr = to->u.FltSave.MxCsr; + } + if (from->flags & SERVER_CTX_DEBUG_REGISTERS) + { + to->ContextFlags |= CONTEXT_DEBUG_REGISTERS; + to->Dr0 = from->debug.x86_64_regs.dr0; + to->Dr1 = from->debug.x86_64_regs.dr1; + to->Dr2 = from->debug.x86_64_regs.dr2; + to->Dr3 = from->debug.x86_64_regs.dr3; + to->Dr6 = from->debug.x86_64_regs.dr6; + to->Dr7 = from->debug.x86_64_regs.dr7; + } + return STATUS_SUCCESS; +} + + /********************************************************************** * get_thread_ldt_entry */ diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 8ea316c10b9..0694426dddb 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -61,6 +61,12 @@ extern void virtual_init(void) DECLSPEC_HIDDEN; extern void CDECL dbg_init(void) DECLSPEC_HIDDEN; extern unsigned int CDECL server_call_unlocked( void *req_ptr ) DECLSPEC_HIDDEN; +extern unsigned int CDECL server_select( const select_op_t *select_op, data_size_t size, UINT flags, + timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, + user_apc_t *user_apc ) DECLSPEC_HIDDEN; +extern unsigned int CDECL server_wait( const select_op_t *select_op, data_size_t size, UINT flags, + const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; +extern unsigned int CDECL server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN; extern void CDECL server_send_fd( int fd ) DECLSPEC_HIDDEN; extern int CDECL server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, @@ -95,6 +101,9 @@ extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; extern void start_server( BOOL debug ) DECLSPEC_HIDDEN; +extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC_HIDDEN; +extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN; + extern void signal_init_threading(void) DECLSPEC_HIDDEN; extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 9b61ff6d4f3..323141d3840 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -27,7 +27,7 @@ struct ldt_copy; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 12 +#define NTDLL_UNIXLIB_VERSION 13 struct unix_funcs { @@ -73,6 +73,12 @@ struct unix_funcs /* server functions */ unsigned int (CDECL *server_call_unlocked)( void *req_ptr ); unsigned int (CDECL *server_call)( void *req_ptr ); + unsigned int (CDECL *server_select)( const select_op_t *select_op, data_size_t size, UINT flags, + timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, + user_apc_t *user_apc ); + unsigned int (CDECL *server_wait)( const select_op_t *select_op, data_size_t size, UINT flags, + const LARGE_INTEGER *timeout ); + unsigned int (CDECL *server_queue_process_apc)( HANDLE process, const apc_call_t *call, apc_result_t *result ); void (CDECL *server_send_fd)( int fd ); int (CDECL *server_get_unix_fd)( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 24f4daf0329..cfe30bbe710 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -2987,7 +2987,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z call.virtual_alloc.zero_bits = zero_bits; call.virtual_alloc.op_type = type; call.virtual_alloc.prot = protect; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_alloc.status == STATUS_SUCCESS) @@ -3115,7 +3115,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si call.virtual_free.addr = wine_server_client_ptr( addr ); call.virtual_free.size = size; call.virtual_free.op_type = type; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_free.status == STATUS_SUCCESS) @@ -3204,7 +3204,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH NtProtectVirtualMemory( HANDLE process, PVOID call.virtual_protect.addr = wine_server_client_ptr( addr ); call.virtual_protect.size = size; call.virtual_protect.prot = new_prot; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_protect.status == STATUS_SUCCESS) @@ -3308,7 +3308,7 @@ static NTSTATUS get_basic_memory_info( HANDLE process, LPCVOID addr, call.virtual_query.type = APC_VIRTUAL_QUERY; call.virtual_query.addr = wine_server_client_ptr( addr ); - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_query.status == STATUS_SUCCESS) @@ -3520,7 +3520,7 @@ NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size, call.virtual_lock.type = APC_VIRTUAL_LOCK; call.virtual_lock.addr = wine_server_client_ptr( *addr ); call.virtual_lock.size = *size; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_lock.status == STATUS_SUCCESS) @@ -3557,7 +3557,7 @@ NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size call.virtual_unlock.type = APC_VIRTUAL_UNLOCK; call.virtual_unlock.addr = wine_server_client_ptr( *addr ); call.virtual_unlock.size = *size; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_unlock.status == STATUS_SUCCESS) @@ -3697,7 +3697,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p call.map_view.zero_bits = zero_bits; call.map_view.alloc_type = alloc_type; call.map_view.prot = protect; - res = server_queue_process_apc( process, &call, &result ); + res = unix_funcs->server_queue_process_apc( process, &call, &result ); if (res != STATUS_SUCCESS) return res; if ((NTSTATUS)result.map_view.status >= 0) @@ -3733,7 +3733,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) call.unmap_view.type = APC_UNMAP_VIEW; call.unmap_view.addr = wine_server_client_ptr( addr ); - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status == STATUS_SUCCESS) status = result.unmap_view.status; return status; } @@ -3872,7 +3872,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr, call.virtual_flush.type = APC_VIRTUAL_FLUSH; call.virtual_flush.addr = wine_server_client_ptr( addr ); call.virtual_flush.size = *size_ptr; - status = server_queue_process_apc( process, &call, &result ); + status = unix_funcs->server_queue_process_apc( process, &call, &result ); if (status != STATUS_SUCCESS) return status; if (result.virtual_flush.status == STATUS_SUCCESS)