[haiku-commits] haiku: hrev52004 - src/system/kernel/arch/x86/64 headers/private/kernel/compat headers/private/kernel/compat/arch/x86 src/system/kernel headers/private/kernel/arch

  • From: Jérôme Duval <jerome.duval@xxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 12 Jun 2018 11:55:21 -0400 (EDT)

hrev52004 adds 1 changeset to branch 'master'
old head: 87628f17eb7ce2cbb0173774e436db1695ebb744
new head: c6e120e2d2f909d95f95839fa99fccf811fdb3c5
overview: 
https://git.haiku-os.org/haiku/log/?qt=range&q=c6e120e2d2f9+%5E87628f17eb7c

----------------------------------------------------------------------------

c6e120e2d2f9: kernel/x86_64: add setup_compat_signal_frame.
  
  * add compatibility signal types.
  
  Change-Id: I665020234be0ba2ccbb33bdbc338c11a214ab6e8

                                   [ Jérôme Duval <jerome.duval@xxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev52004
Commit:      c6e120e2d2f909d95f95839fa99fccf811fdb3c5
URL:         https://git.haiku-os.org/haiku/commit/?id=c6e120e2d2f9
Author:      Jérôme Duval <jerome.duval@xxxxxxxxx>
Date:        Tue May 15 19:19:38 2018 UTC

----------------------------------------------------------------------------

7 files changed, 593 insertions(+), 13 deletions(-)
headers/private/kernel/arch/thread.h             |   6 +
headers/private/kernel/arch/x86/arch_thread.h    |  24 +++
.../kernel/compat/arch/x86/signal_compat.h       | 113 ++++++++++
headers/private/kernel/compat/ksignal_compat.h   | 164 ++++++++++++++
headers/private/kernel/compat/signal_compat.h    |  22 ++
src/system/kernel/arch/x86/64/thread.cpp         | 214 +++++++++++++++++--
src/system/kernel/signal.cpp                     |  63 ++++++

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/arch/thread.h 
b/headers/private/kernel/arch/thread.h
index b19066a520..5556073300 100644
--- a/headers/private/kernel/arch/thread.h
+++ b/headers/private/kernel/arch/thread.h
@@ -31,6 +31,12 @@ bool arch_on_signal_stack(Thread *thread);
 status_t arch_setup_signal_frame(Thread *thread, struct sigaction *action,
        struct signal_frame_data *signalFrameData);
 int64 arch_restore_signal_frame(struct signal_frame_data* signalFrameData);
+#ifdef _COMPAT_MODE
+status_t arch_setup_compat_signal_frame(Thread *thread,
+       struct sigaction *action, struct compat_signal_frame_data 
*signalFrameData);
+int64 arch_restore_compat_signal_frame(
+       struct compat_signal_frame_data* signalFrameData);
+#endif
 
 void arch_store_fork_frame(struct arch_fork_arg *arg);
 void arch_restore_fork_frame(struct arch_fork_arg *arg);
diff --git a/headers/private/kernel/arch/x86/arch_thread.h 
b/headers/private/kernel/arch/x86/arch_thread.h
index 3689d0b44b..2415110df8 100644
--- a/headers/private/kernel/arch/x86/arch_thread.h
+++ b/headers/private/kernel/arch/x86/arch_thread.h
@@ -51,6 +51,30 @@ arch_thread_set_current_thread(Thread* t)
 }
 
 
+#ifdef _COMPAT_MODE
+
+
+static inline void
+arch_thread_set_ds(unsigned short ds)
+{
+       asm volatile("mov %0, %%ds" : : "r" (ds) : "memory");
+}
+
+
+static inline void
+arch_thread_set_es(unsigned short es)
+{
+       asm volatile("mov %0, %%es" : : "r" (es) : "memory");
+}
+
+// override empty macro
+#undef arch_syscall_64_bit_return_value
+void arch_syscall_64_bit_return_value(void);
+
+
+#endif // _COMPAT_MODE
+
+
 #else  // __x86_64__
 
 
diff --git a/headers/private/kernel/compat/arch/x86/signal_compat.h 
b/headers/private/kernel/compat/arch/x86/signal_compat.h
new file mode 100644
index 0000000000..8fe645d44c
--- /dev/null
+++ b/headers/private/kernel/compat/arch/x86/signal_compat.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_ARCH_SIGNAL_H
+#define _KERNEL_COMPAT_ARCH_SIGNAL_H
+
+
+typedef struct packed_fp_stack {
+       unsigned char   st0[10];
+       unsigned char   st1[10];
+       unsigned char   st2[10];
+       unsigned char   st3[10];
+       unsigned char   st4[10];
+       unsigned char   st5[10];
+       unsigned char   st6[10];
+       unsigned char   st7[10];
+} packed_fp_stack;
+
+typedef struct packed_mmx_regs {
+       unsigned char   mm0[10];
+       unsigned char   mm1[10];
+       unsigned char   mm2[10];
+       unsigned char   mm3[10];
+       unsigned char   mm4[10];
+       unsigned char   mm5[10];
+       unsigned char   mm6[10];
+       unsigned char   mm7[10];
+} packed_mmx_regs;
+
+typedef struct xmmx_regs {
+       unsigned char   xmm0[16];
+       unsigned char   xmm1[16];
+       unsigned char   xmm2[16];
+       unsigned char   xmm3[16];
+       unsigned char   xmm4[16];
+       unsigned char   xmm5[16];
+       unsigned char   xmm6[16];
+       unsigned char   xmm7[16];
+} xmmx_regs;
+
+typedef struct compat_stack_t {
+       uint32  ss_sp;
+       uint32  ss_size;
+       int             ss_flags;
+} compat_stack_t;
+
+typedef struct compat_old_extended_regs {
+       unsigned short  fp_control;
+       unsigned short  _reserved1;
+       unsigned short  fp_status;
+       unsigned short  _reserved2;
+       unsigned short  fp_tag;
+       unsigned short  _reserved3;
+       uint32  fp_eip;
+       unsigned short  fp_cs;
+       unsigned short  fp_opcode;
+       uint32  fp_datap;
+       unsigned short  fp_ds;
+       unsigned short  _reserved4;
+       union {
+               packed_fp_stack fp;
+               packed_mmx_regs mmx;
+       } fp_mmx;
+} compat_old_extended_regs;
+
+typedef struct compat_new_extended_regs {
+       unsigned short  fp_control;
+       unsigned short  fp_status;
+       unsigned short  fp_tag;
+       unsigned short  fp_opcode;
+       uint32  fp_eip;
+       unsigned short  fp_cs;
+       unsigned short  res_14_15;
+       uint32  fp_datap;
+       unsigned short  fp_ds;
+       unsigned short  _reserved_22_23;
+       uint32  mxcsr;
+       uint32  _reserved_28_31;
+       union {
+               fp_stack fp;
+               mmx_regs mmx;
+       } fp_mmx;
+       xmmx_regs xmmx;
+       unsigned char   _reserved_288_511[224];
+} compat_new_extended_regs;
+
+typedef struct compat_extended_regs {
+       union {
+               compat_old_extended_regs        old_format;
+               compat_new_extended_regs        new_format;
+       } state;
+       uint32  format;
+} compat_extended_regs;
+
+struct compat_vregs {
+       uint32                  eip;
+       uint32                  eflags;
+       uint32                  eax;
+       uint32                  ecx;
+       uint32                  edx;
+       uint32                  esp;
+       uint32                  ebp;
+       uint32                  _reserved_1;
+       compat_extended_regs    xregs;
+       uint32                  edi;
+       uint32                  esi;
+       uint32                  ebx;
+};
+
+
+#endif // _KERNEL_COMPAT_ARCH_SIGNAL_H
diff --git a/headers/private/kernel/compat/ksignal_compat.h 
b/headers/private/kernel/compat/ksignal_compat.h
new file mode 100644
index 0000000000..6b3ee64a38
--- /dev/null
+++ b/headers/private/kernel/compat/ksignal_compat.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_KSIGNAL_H
+#define _KERNEL_COMPAT_KSIGNAL_H
+
+
+#include <compat/signal_compat.h>
+#include <compat/arch/x86/signal_compat.h>
+
+
+typedef struct compat_vregs compat_mcontext_t;
+
+typedef struct __compat_ucontext_t {
+       uint32                                  uc_link;
+       sigset_t                                uc_sigmask;
+       compat_stack_t                  uc_stack;
+       compat_mcontext_t               uc_mcontext;
+} _PACKED compat_ucontext_t;
+
+union compat_sigval {
+       int             sival_int;
+       uint32  sival_ptr;
+};
+
+
+typedef struct __compat_siginfo_t {
+       int                             si_signo;       /* signal number */
+       int                             si_code;        /* signal code */
+       int                             si_errno;       /* if non zero, an 
error number associated with
+                                                                  this signal 
*/
+       pid_t                   si_pid;         /* sending process ID */
+       uid_t                   si_uid;         /* real user ID of sending 
process */
+       uint32                  si_addr;        /* address of faulting 
instruction */
+       int                             si_status;      /* exit value or signal 
*/
+       uint32                  si_band;        /* band event for SIGPOLL */
+       union compat_sigval     si_value;       /* signal value */
+} compat_siginfo_t;
+
+struct compat_signal_frame_data {
+       compat_siginfo_t        info;
+       compat_ucontext_t       context;
+       uint32          user_data;
+       uint32          handler;
+       bool            siginfo_handler;
+       char            _pad[3];
+       int32           thread_flags;
+       uint64          syscall_restart_return_value;
+       uint8           
syscall_restart_parameters[SYSCALL_RESTART_PARAMETER_SIZE];
+       uint32          commpage_address;
+} _PACKED;
+
+
+static_assert(sizeof(compat_stack_t) == 12,
+       "size of compat_stack_t mismatch");
+static_assert(sizeof(compat_mcontext_t) == 560,
+       "size of compat_mcontext_t mismatch");
+static_assert(sizeof(compat_ucontext_t) == 584,
+       "size of compat_ucontext_t mismatch");
+static_assert(sizeof(compat_siginfo_t) == 36,
+       "size of compat_siginfo_t mismatch");
+static_assert(sizeof(struct compat_signal_frame_data) == 680,
+       "size of compat_signal_frame_data mismatch");
+
+
+inline status_t
+copy_ref_var_from_user(union sigval* userSigval, union sigval &sigval)
+{
+       if (!IS_USER_ADDRESS(userSigval))
+               return B_BAD_ADDRESS;
+       Thread* thread = thread_get_current_thread();
+       bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+       if (compatMode) {
+               compat_sigval compat_sigval;
+               if (user_memcpy(&compat_sigval, userSigval, 
sizeof(compat_sigval))
+                               < B_OK) {
+                       return B_BAD_ADDRESS;
+               }
+               sigval.sival_ptr = (void*)(addr_t)compat_sigval.sival_ptr;
+       } else if (user_memcpy(&sigval, userSigval, sizeof(union sigval)) < 
B_OK) {
+               return B_BAD_ADDRESS;
+       }
+       return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(siginfo_t &info, siginfo_t* userInfo)
+{
+       if (!IS_USER_ADDRESS(userInfo))
+               return B_BAD_ADDRESS;
+       Thread* thread = thread_get_current_thread();
+       bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+       if (compatMode) {
+               compat_siginfo_t compat_info;
+               compat_info.si_signo = info.si_signo;
+               compat_info.si_code = info.si_code;
+               compat_info.si_errno = info.si_errno;
+               compat_info.si_pid = info.si_pid;
+               compat_info.si_uid = info.si_uid;
+               compat_info.si_addr = (addr_t)info.si_addr;
+               compat_info.si_status = info.si_status;
+               compat_info.si_band = info.si_band;
+               compat_info.si_value.sival_ptr = 
(addr_t)info.si_value.sival_ptr;
+               if (user_memcpy(userInfo, &compat_info, sizeof(compat_info))
+                               < B_OK) {
+                       return B_BAD_ADDRESS;
+               }
+       } else if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK) {
+               return B_BAD_ADDRESS;
+       }
+       return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(stack_t* userStack, stack_t &stack)
+{
+       if (!IS_USER_ADDRESS(userStack))
+               return B_BAD_ADDRESS;
+       Thread* thread = thread_get_current_thread();
+       bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+       if (compatMode) {
+               compat_stack_t compatStack;
+               if (user_memcpy(&compatStack, userStack, sizeof(compatStack))
+                               < B_OK) {
+                       return B_BAD_ADDRESS;
+               }
+               stack.ss_sp = (void*)(addr_t)compatStack.ss_sp;
+               stack.ss_size = compatStack.ss_size;
+               stack.ss_flags = compatStack.ss_flags;
+       } else if (user_memcpy(&stack, userStack, sizeof(stack_t)) < B_OK) {
+               return B_BAD_ADDRESS;
+       }
+       return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(stack_t &stack, stack_t* userStack)
+{
+       if (!IS_USER_ADDRESS(userStack))
+               return B_BAD_ADDRESS;
+       Thread* thread = thread_get_current_thread();
+       bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+       if (compatMode) {
+               compat_stack_t compatStack;
+               compatStack.ss_sp = (addr_t)stack.ss_sp;
+               compatStack.ss_size = stack.ss_size;
+               compatStack.ss_flags = stack.ss_flags;
+               if (user_memcpy(userStack, &compatStack, sizeof(compatStack))
+                               < B_OK) {
+                       return B_BAD_ADDRESS;
+               }
+       } else if (user_memcpy(userStack, &stack, sizeof(stack)) < B_OK) {
+               return B_BAD_ADDRESS;
+       }
+       return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_KSIGNAL_H
diff --git a/headers/private/kernel/compat/signal_compat.h 
b/headers/private/kernel/compat/signal_compat.h
new file mode 100644
index 0000000000..07a4686296
--- /dev/null
+++ b/headers/private/kernel/compat/signal_compat.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_SIGNAL_H
+#define _KERNEL_COMPAT_SIGNAL_H
+
+
+struct compat_sigaction {
+       union {
+               uint32          sa_handler;
+               uint32          sa_sigaction;
+       };
+       sigset_t                                sa_mask;
+       int                                             sa_flags;
+       uint32                                  sa_userdata;    /* will be 
passed to the signal
+                                                                               
           handler, BeOS extension */
+} _PACKED;
+
+
+#endif // _KERNEL_COMPAT_SIGNAL_H
diff --git a/src/system/kernel/arch/x86/64/thread.cpp 
b/src/system/kernel/arch/x86/64/thread.cpp
index a29697a03f..7a6a35d724 100644
--- a/src/system/kernel/arch/x86/64/thread.cpp
+++ b/src/system/kernel/arch/x86/64/thread.cpp
@@ -18,6 +18,9 @@
 #include <debug.h>
 #include <kernel.h>
 #include <ksignal.h>
+#ifdef _COMPAT_MODE
+#      include <compat/ksignal_compat.h>
+#endif
 #include <int.h>
 #include <team.h>
 #include <thread.h>
@@ -88,11 +91,33 @@ x86_restart_syscall(iframe* frame)
 }
 
 
+#ifdef _COMPAT_MODE
+
+
+static inline void
+set_fs_register(uint32 segment)
+{
+       asm("movl %0,%%fs" :: "r" (segment));
+}
+
+
+#endif // _COMPAT_MODE
+
+
 void
 x86_set_tls_context(Thread* thread)
 {
-       // Set FS segment base address to the TLS segment.
-       x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
+#ifdef _COMPAT_MODE
+       if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+               unsigned index = x86_64_set_user_tls_segment_base(
+                       smp_get_current_cpu(), thread->user_local_storage);
+               set_fs_register((index << 3) | DPL_USER);
+       } else
+#endif
+       {
+               // Set FS segment base address to the TLS segment.
+               x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
+       }
 }
 
 
@@ -109,6 +134,24 @@ arch_randomize_stack_pointer(addr_t value)
 }
 
 
+#ifdef _COMPAT_MODE
+
+
+static addr_t
+arch_compat_randomize_stack_pointer(addr_t value)
+{
+       STATIC_ASSERT(MAX_RANDOM_VALUE >= B_PAGE_SIZE - 1);
+       value -= random_value() & (B_PAGE_SIZE - 1);
+       return (value & ~addr_t(0xf)) - 4;
+               // This means, result % 16 == 12, which is what esp should 
adhere to
+               // when a function is entered for the stack to be considered 
aligned to
+               // 16 byte.
+}
+
+
+#endif // _COMPAT_MODE
+
+
 static uint8*
 get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action,
        size_t spaceNeeded)
@@ -218,27 +261,55 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, 
void* args1,
        TRACE("arch_thread_enter_userspace: entry %#lx, args %p %p, "
                "stackTop %#lx\n", entry, args1, args2, stackTop);
 
-       stackTop = arch_randomize_stack_pointer(stackTop - sizeof(codeAddr));
-
        // Copy the address of the stub that calls exit_thread() when the thread
        // entry function returns to the top of the stack to act as the return
        // address. The stub is inside commpage.
        addr_t commPageAddress = (addr_t)thread->team->commpage_address;
-       set_ac();
-       codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
-               + commPageAddress;
-       clear_ac();
-       if (user_memcpy((void*)stackTop, (const void*)&codeAddr, 
sizeof(codeAddr))
+
+#ifdef _COMPAT_MODE
+       if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+               uint32 args[3];
+               stackTop = arch_compat_randomize_stack_pointer(stackTop - 
sizeof(args));
+
+               set_ac();
+               args[0] = 
((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
+                       + commPageAddress;
+               clear_ac();
+               args[1] = (uint32)(addr_t)args1;
+               args[2] = (uint32)(addr_t)args2;
+               if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
+                       return B_BAD_ADDRESS;
+
+       } else
+#endif
+       {
+               stackTop = arch_randomize_stack_pointer(stackTop - 
sizeof(codeAddr));
+
+               set_ac();
+               codeAddr = 
((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
+                       + commPageAddress;
+               clear_ac();
+               if (user_memcpy((void*)stackTop, (const void*)&codeAddr, 
sizeof(codeAddr))
                        != B_OK)
-               return B_BAD_ADDRESS;
+                       return B_BAD_ADDRESS;
+       }
 
        // Prepare the user iframe.
        iframe frame = {};
        frame.type = IFRAME_TYPE_SYSCALL;
-       frame.si = (uint64)args2;
-       frame.di = (uint64)args1;
        frame.ip = entry;
-       frame.cs = USER_CODE_SELECTOR;
+#ifdef _COMPAT_MODE
+       if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+               frame.cs = USER32_CODE_SELECTOR;
+               arch_thread_set_ds(USER_DATA_SELECTOR);
+               arch_thread_set_es(USER_DATA_SELECTOR);
+       } else
+#endif
+       {
+               frame.si = (uint64)args2;
+               frame.di = (uint64)args1;
+               frame.cs = USER_CODE_SELECTOR;
+       }
        frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
                | (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
        frame.sp = stackTop;
@@ -394,3 +465,120 @@ arch_restore_signal_frame(struct signal_frame_data* 
signalFrameData)
        // restored.
        return frame->ax;
 }
+
+
+#ifdef _COMPAT_MODE
+
+status_t
+arch_setup_compat_signal_frame(Thread* thread, struct sigaction* action,
+       struct compat_signal_frame_data* signalFrameData)
+{
+       iframe* frame = x86_get_current_iframe();
+       if (!IFRAME_IS_USER(frame)) {
+               panic("arch_setup_compat_signal_frame(): No user iframe!");
+               return B_BAD_VALUE;
+       }
+
+       // Store the register state.
+       signalFrameData->context.uc_mcontext.eax = frame->ax;
+       signalFrameData->context.uc_mcontext.ebx = frame->bx;
+       signalFrameData->context.uc_mcontext.ecx = frame->cx;
+       signalFrameData->context.uc_mcontext.edx = frame->dx;
+       signalFrameData->context.uc_mcontext.edi = frame->di;
+       signalFrameData->context.uc_mcontext.esi = frame->si;
+       signalFrameData->context.uc_mcontext.ebp = frame->bp;
+       signalFrameData->context.uc_mcontext.esp = frame->user_sp;
+       signalFrameData->context.uc_mcontext.eip = frame->ip;
+       signalFrameData->context.uc_mcontext.eflags = frame->flags;
+       x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
+
+       // Fill in signalFrameData->context.uc_stack.
+       stack_t stack;
+       signal_get_user_stack(frame->user_sp, &stack);
+       signalFrameData->context.uc_stack.ss_sp = (addr_t)stack.ss_sp;
+       signalFrameData->context.uc_stack.ss_size = stack.ss_size;
+       signalFrameData->context.uc_stack.ss_flags = stack.ss_flags;
+
+       // Store syscall_restart_return_value.
+       signalFrameData->syscall_restart_return_value = frame->orig_rax;
+
+       // Get the stack to use and copy the frame data to it.
+       uint32 stackFrame[2];
+       uint8* userStack = get_signal_stack(thread, frame, action,
+               sizeof(*signalFrameData) + sizeof(stackFrame));
+
+       compat_signal_frame_data* userSignalFrameData
+               = (compat_signal_frame_data*)(userStack + sizeof(stackFrame));
+
+       if (user_memcpy(userSignalFrameData, signalFrameData,
+                       sizeof(*signalFrameData)) != B_OK) {
+               return B_BAD_ADDRESS;
+       }
+
+       // prepare the user stack frame for a function call to the signal 
handler
+       // wrapper function
+       stackFrame[0] = frame->ip;
+       stackFrame[1] = (addr_t)userSignalFrameData;
+               // parameter: pointer to signal frame data
+
+       if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
+               return B_BAD_ADDRESS;
+
+       // Update Thread::user_signal_context, now that everything seems to have
+       // gone fine.
+       thread->user_signal_context = 
(ucontext_t*)&userSignalFrameData->context;
+
+       // Set up the iframe to execute the signal handler wrapper on our 
prepared
+       // stack. First argument points to the frame data.
+       addr_t* commPageAddress = (addr_t*)thread->team->commpage_address;
+       frame->user_sp = (addr_t)userStack;
+       set_ac();
+
+       // from x86/arch_commpage_defs.h
+#define COMPAT_COMMPAGE_ENTRY_X86_SIGNAL_HANDLER \
+       (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 3)
+       frame->ip = commPageAddress[COMPAT_COMMPAGE_ENTRY_X86_SIGNAL_HANDLER]
+               + (addr_t)commPageAddress;
+       clear_ac();
+
+       return B_OK;
+}
+
+
+int64
+arch_restore_compat_signal_frame(struct compat_signal_frame_data* 
signalFrameData)
+{
+       iframe* frame = x86_get_current_iframe();
+
+       frame->orig_rax = signalFrameData->syscall_restart_return_value;
+       frame->ax = signalFrameData->context.uc_mcontext.eax;
+       frame->bx = signalFrameData->context.uc_mcontext.ebx;
+       frame->cx = signalFrameData->context.uc_mcontext.ecx;
+       frame->dx = signalFrameData->context.uc_mcontext.edx;
+       frame->di = signalFrameData->context.uc_mcontext.edi;
+       frame->si = signalFrameData->context.uc_mcontext.esi;
+       frame->bp = signalFrameData->context.uc_mcontext.ebp;
+       frame->user_sp = signalFrameData->context.uc_mcontext.esp;
+       frame->ip = signalFrameData->context.uc_mcontext.eip;
+       frame->flags = (frame->flags & ~(uint64)X86_EFLAGS_USER_FLAGS)
+               | (signalFrameData->context.uc_mcontext.eflags & 
X86_EFLAGS_USER_FLAGS);
+
+       x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
+
+       // The syscall return code overwrites frame->ax with the return value of
+       // the syscall, need to return it here to ensure the correct value is
+       // restored.
+       return frame->ax;
+}
+
+
+void
+arch_syscall_64_bit_return_value(void)
+{
+       Thread* thread = thread_get_current_thread();
+       if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+               atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
+}
+
+#endif // _COMPAT_MODE
+
diff --git a/src/system/kernel/signal.cpp b/src/system/kernel/signal.cpp
index cea1c3168e..3f96d7918d 100644
--- a/src/system/kernel/signal.cpp
+++ b/src/system/kernel/signal.cpp
@@ -13,6 +13,9 @@
 
 
 #include <ksignal.h>
+#ifdef _COMPAT_MODE
+#      include <compat/ksignal.h>
+#endif
 
 #include <errno.h>
 #include <stddef.h>
@@ -908,6 +911,61 @@ setup_signal_frame(Thread* thread, struct sigaction* 
action, Signal* signal,
 }
 
 
+#ifdef _COMPAT_MODE
+
+static status_t
+setup_compat_signal_frame(Thread* thread, struct sigaction* action, Signal* 
signal,
+       sigset_t signalMask)
+{
+       // prepare the data, we need to copy onto the user stack
+       struct compat_signal_frame_data frameData;
+
+       // signal info
+       frameData.info.si_signo = signal->Number();
+       frameData.info.si_code = signal->SignalCode();
+       frameData.info.si_errno = signal->ErrorCode();
+       frameData.info.si_pid = signal->SendingProcess();
+       frameData.info.si_uid = signal->SendingUser();
+       frameData.info.si_addr = (addr_t)signal->Address();
+       frameData.info.si_status = signal->Status();
+       frameData.info.si_band = signal->PollBand();
+       frameData.info.si_value.sival_ptr = 
(addr_t)signal->UserValue().sival_ptr;
+
+       // context
+       frameData.context.uc_link = (addr_t)thread->user_signal_context;
+       frameData.context.uc_sigmask = signalMask;
+       // uc_stack and uc_mcontext are filled in by the architecture specific 
code.
+
+       // user data
+       frameData.user_data = (addr_t)action->sa_userdata;
+
+       // handler function
+       frameData.siginfo_handler = (action->sa_flags & SA_SIGINFO) != 0;
+       frameData.handler = frameData.siginfo_handler
+               ? (addr_t)action->sa_sigaction : (addr_t)action->sa_handler;
+
+       // thread flags -- save the and clear the thread's syscall restart 
related
+       // flags
+       frameData.thread_flags = atomic_and(&thread->flags,
+               ~(THREAD_FLAGS_RESTART_SYSCALL | 
THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
+
+       // syscall restart related fields
+       memcpy(frameData.syscall_restart_parameters,
+               thread->syscall_restart.parameters,
+               sizeof(frameData.syscall_restart_parameters));
+
+       // commpage address
+       frameData.commpage_address = (addr_t)thread->team->commpage_address;
+
+       // syscall_restart_return_value is filled in by the architecture 
specific
+       // code.
+
+       return arch_setup_compat_signal_frame(thread, action, &frameData);
+}
+
+#endif // _COMPAT_MODE
+
+
 /*! Actually handles pending signals -- i.e. the thread will exit, a custom
        signal handler is prepared, or whatever the signal demands.
        The function will not return, when a deadly signal is encountered. The
@@ -1258,6 +1316,11 @@ handle_signals(Thread* thread)
 
                locker.Unlock();
 
+#ifdef _COMPAT_MODE
+               if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
+                       setup_compat_signal_frame(thread, &handler, signal, 
oldBlockMask);
+               else
+#endif
                setup_signal_frame(thread, &handler, signal, oldBlockMask);
 
                // Reset sigsuspend_original_unblocked_mask. It would have been 
set by


Other related posts:

  • » [haiku-commits] haiku: hrev52004 - src/system/kernel/arch/x86/64 headers/private/kernel/compat headers/private/kernel/compat/arch/x86 src/system/kernel headers/private/kernel/arch - Jérôme Duval