qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 04/23] bsd-user: add bsd signal emulation


From: Stacey Son
Subject: [Qemu-devel] [PATCH 04/23] bsd-user: add bsd signal emulation
Date: Sun, 23 Jun 2013 21:03:36 -0500

Add bsd-user signal emulation code, fix name space confict with sigqueue, add
arch dependent code for mips/mips64, and OS dependent definitions for FreeBSD.

Signed-off-by: Stacey Son <address@hidden>
---
 bsd-user/freebsd/target_os_signal.h   |    9 +
 bsd-user/i386/target_arch_signal.h    |   39 ++
 bsd-user/i386/target_arch_vmparam.h   |    2 -
 bsd-user/mips/target_arch_signal.h    |  160 ++++++
 bsd-user/mips/target_arch_vmparam.h   |    6 +-
 bsd-user/mips64/target_arch_signal.h  |  159 ++++++
 bsd-user/qemu.h                       |   33 +-
 bsd-user/signal.c                     |  922 +++++++++++++++++++++++++++++++++
 bsd-user/sparc/target_arch_signal.h   |   39 ++
 bsd-user/sparc64/target_arch_signal.h |   39 ++
 bsd-user/x86_64/target_arch_signal.h  |   39 ++
 11 files changed, 1429 insertions(+), 18 deletions(-)

diff --git a/bsd-user/freebsd/target_os_signal.h 
b/bsd-user/freebsd/target_os_signal.h
index 3421a4e..d7004c8 100644
--- a/bsd-user/freebsd/target_os_signal.h
+++ b/bsd-user/freebsd/target_os_signal.h
@@ -52,6 +52,15 @@
 #define TARGET_SIG_IGN      ((abi_long)1)   /* ignore signal */
 #define TARGET_SIG_ERR      ((abi_long)-1)  /* error return from signal */
 
+#define TARGET_SA_ONSTACK   0x0001  /* take signal on signal stack */
+#define TARGET_SA_RESTART   0x0002  /* restart system on signal return */
+#define TARGET_SA_RESETHAND 0x0004  /* reset to SIG_DFL when taking signal */
+#define TARGET_SA_NODEFER   0x0010  /* don't mask the signal we're delivering 
*/
+#define TARGET_SA_NOCLDWAIT 0x0020  /* don't create zombies (assign to pid 1) 
*/
+#define TARGET_SA_USERTRAMP 0x0100  /* do not bounce off kernel's sigtramp */
+#define TARGET_SA_NOCLDSTOP 0x0008  /* do not generate SIGCHLD on child stop */
+#define TARGET_SA_SIGINFO   0x0040  /* generate siginfo_t */
+
 /*
  * Flags for sigprocmask:
  */
diff --git a/bsd-user/i386/target_arch_signal.h 
b/bsd-user/i386/target_arch_signal.h
index ebd83f6..2e89529 100644
--- a/bsd-user/i386/target_arch_signal.h
+++ b/bsd-user/i386/target_arch_signal.h
@@ -20,4 +20,43 @@
 
 #include "cpu.h"
 
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    return -TARGET_EOPNOTSUPP;
+}
+
 #endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/i386/target_arch_vmparam.h 
b/bsd-user/i386/target_arch_vmparam.h
index 6687adb..6d3cf4f 100644
--- a/bsd-user/i386/target_arch_vmparam.h
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -13,8 +13,6 @@
 
 #define TARGET_USRSTACK (0xbfc00000)
 
-#define TARGET_PS_STRINGS  (TARGET_USRSTACK - sizeof(struct target_ps_strings))
-
 static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
 {
     return state->regs[R_ESP];
diff --git a/bsd-user/mips/target_arch_signal.h 
b/bsd-user/mips/target_arch_signal.h
index 256c135..cc7e750 100644
--- a/bsd-user/mips/target_arch_signal.h
+++ b/bsd-user/mips/target_arch_signal.h
@@ -22,6 +22,23 @@
 
 #define TARGET_INSN_SIZE    4       /* mips instruction size */
 
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+/* compare to mips/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)                   /* min sig stack size 
*/
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)  /* recommended size 
*/
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
 struct target_sigcontext {
     target_sigset_t sc_mask;    /* signal mask to retstore */
     int32_t     sc_onstack;     /* sigstack state to restore */
@@ -65,4 +82,147 @@ struct target_sigframe {
     uint32_t    __spare__[2];
 };
 
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = (abi_ulong)&frame->sf_si;
+    frame->sf_ucontext = (abi_ulong)&frame->sf_uc;
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long
+get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
 #endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/mips/target_arch_vmparam.h 
b/bsd-user/mips/target_arch_vmparam.h
index 0480035..8f8bc9e 100644
--- a/bsd-user/mips/target_arch_vmparam.h
+++ b/bsd-user/mips/target_arch_vmparam.h
@@ -1,5 +1,5 @@
 /*
- *  mips64 VM parameters definitions
+ *  mips VM parameters definitions
  *
  *  Copyright (c) 2013 Stacey D. Son
  *
@@ -29,8 +29,8 @@
 #define TARGET_MAXSSIZ      (64UL*1024*1024)    /* max stack size */
 #define TARGET_SGROWSIZ     (128UL*1024)        /* amount to grow stack */
 
-#define TARGET_VM_MINUSER_ADDRESS   (0x0000000000000000UL)
-#define TARGET_VM_MAXUSER_ADDRESS   (0x0000008000000000UL)
+#define TARGET_VM_MINUSER_ADDRESS   (0x00000000)
+#define TARGET_VM_MAXUSER_ADDRESS   (0x80000000)
 
 #define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
 
diff --git a/bsd-user/mips64/target_arch_signal.h 
b/bsd-user/mips64/target_arch_signal.h
index 27aa700..5edcc3a 100644
--- a/bsd-user/mips64/target_arch_signal.h
+++ b/bsd-user/mips64/target_arch_signal.h
@@ -22,6 +22,22 @@
 
 #define TARGET_INSN_SIZE     4  /* mips64 instruction size */
 
+/* Size of the signal trampolin code placed on the stack. */
+#define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
+
+#define TARGET_MINSIGSTKSZ  (512 * 4)
+#define TARGET_SIGSTKSZ     (TARGET_MINSIGSTKSZ + 32768)
+
+/* compare to sys/mips/include/asm.h */
+#define TARGET_SZREG        8
+#define TARGET_CALLFRAME_SIZ    (TARGET_SZREG * 4)
+
+/* mips/mips/pm_machdep.c */
+#define TARGET_UCONTEXT_MAGIC   0xACEDBADE
+#define TARGET_MC_GET_CLEAR_RET 0x0001
+#define TARGET_MC_ADD_MAGIC     0x0002
+#define TARGET_MC_SET_ONSTACK   0x0004
+
 struct target_sigcontext {
     target_sigset_t sc_mask;    /* signal mask to retstore */
     int32_t     sc_onstack;     /* sigstack state to restore */
@@ -65,4 +81,147 @@ struct target_sigframe {
     uint32_t    __spare__[2];
 };
 
+/*
+ * Compare to mips/mips/pm_machdep.c sendsig()
+ * Assumes that target stack frame memory is locked.
+ */
+static inline abi_long
+set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
+    abi_ulong frame_addr, struct target_sigaction *ka)
+{
+
+    /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */
+
+    /* MIPS only struct target_sigframe members: */
+    frame->sf_signum = sig;
+    frame->sf_siginfo = (abi_ulong)&frame->sf_si;
+    frame->sf_ucontext = (abi_ulong)&frame->sf_uc;
+
+    /*
+     * Arguments to signal handler:
+     *  a0 ($4) = signal number
+     *  a1 ($5) = siginfo pointer
+     *  a2 ($6) = ucontext pointer
+     *  PC = signal handler pointer
+     *  t9 ($25) = signal handler pointer
+     *  $29 = point to sigframe struct
+     *  ra ($31) = sigtramp at base of user stack
+     */
+    regs->active_tc.gpr[4] = sig;
+    regs->active_tc.gpr[5] = frame_addr +
+        offsetof(struct target_sigframe, sf_si);
+    regs->active_tc.gpr[6] = frame_addr +
+        offsetof(struct target_sigframe, sf_uc);
+    regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler;
+    regs->active_tc.gpr[29] = frame_addr;
+    regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+    return 0;
+}
+
+/*
+ * Compare to mips/mips/pm_machdep.c get_mcontext()
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+static inline abi_long
+get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags)
+{
+    int i, err = 0;
+
+    if (flags & TARGET_MC_ADD_MAGIC) {
+        mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC);
+    } else {
+        mcp->mc_regs[0] = 0;
+    }
+
+    if (flags & TARGET_MC_SET_ONSTACK) {
+        mcp->mc_onstack = tswapal(1);
+    } else {
+        mcp->mc_onstack = 0;
+    }
+
+    for (i = 1; i < 32; i++) {
+        mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]);
+    }
+
+#if 0 /* XXX FP is not used right now */
+    abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0;
+
+    mcp->mc_fpused = used_fp;
+    if (used_fp) {
+        preempt_disable();
+        if (!is_fpu_owner()) {
+            own_fpu();
+            for (i = 0; i < 33; i++) {
+                mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]);
+            }
+        }
+        preempt_enable();
+    }
+#else
+    mcp->mc_fpused = 0;
+#endif
+
+    if (flags & TARGET_MC_GET_CLEAR_RET) {
+        mcp->mc_regs[2] = 0;    /* v0 = 0 */
+        mcp->mc_regs[3] = 0;    /* v1 = 0 */
+        mcp->mc_regs[7] = 0;    /* a3 = 0 */
+    }
+
+    mcp->mc_pc = tswapal(regs->active_tc.PC);
+    mcp->mullo = tswapal(regs->active_tc.LO[0]);
+    mcp->mulhi = tswapal(regs->active_tc.HI[0]);
+    mcp->mc_tls = tswapal(regs->tls_value);
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
+/* Compare to mips/mips/pm_machdep.c set_mcontext() */
+static inline abi_long set_mcontext(CPUMIPSState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    int i, err = 0;
+
+    for (i = 1; i < 32; i++) {
+        regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]);
+    }
+
+#if 0  /* XXX FP is not used right now */
+    abi_ulong used_fp = 0;
+
+    used_fp = tswapal(mcp->mc_fpused)
+    conditional_used_math(used_fp);
+
+    preempt_disabled();
+    if (used_math()) {
+        /* restore fpu context if we have used it before */
+        own_fpu();
+        for (i = 0; i < 32; i++) {
+            regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]);
+        }
+    } else {
+        /* Signal handler may have used FPU.  Give it up. */
+        lose_fpu();
+    }
+    preempt_enable();
+#endif
+
+    regs->CP0_EPC = tswapal(mcp->mc_pc);
+    regs->active_tc.LO[0] = tswapal(mcp->mullo);
+    regs->active_tc.HI[0] = tswapal(mcp->mulhi);
+    regs->tls_value = tswapal(mcp->mc_tls);
+
+    if (srflag) {
+        /* doing sigreturn() */
+        regs->active_tc.PC = regs->CP0_EPC;
+        regs->CP0_EPC = 0;  /* XXX  for nested signals ? */
+    }
+
+    /* Don't do any of the status and cause registers. */
+
+    return err;
+}
+
 #endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 63a3942..c0cdfcd 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -38,8 +38,8 @@ extern enum BSDType bsd_type;
 
 #include "syscall_defs.h"
 #include "syscall.h"
-#include "target_os_signal.h"
 #include "target_os_vmparam.h"
+#include "target_os_signal.h"
 #include "exec/gdbstub.h"
 
 #if defined(CONFIG_USE_NPTL)
@@ -72,16 +72,16 @@ struct image_info {
 
 #define MAX_SIGQUEUE_SIZE 1024
 
-struct sigqueue {
-    struct sigqueue *next;
-    //target_siginfo_t info;
+struct qemu_sigqueue {
+    struct qemu_sigqueue *next;
+    target_siginfo_t info;
 };
 
 struct emulated_sigtable {
     int pending; /* true if signal is pending */
-    struct sigqueue *first;
-    struct sigqueue info; /* in order to always have memory for the
-                             first signal, we put it here */
+    struct qemu_sigqueue *first;
+    struct qemu_sigqueue info; /* in order to always have memory for the
+                                  first signal, we put it here */
 };
 
 /* NOTE: we force a big alignment so that the stack stored after is
@@ -92,8 +92,8 @@ typedef struct TaskState {
     struct image_info *info;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
-    struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
-    struct sigqueue *first_free; /* first free siginfo queue entry */
+    struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+    struct qemu_sigqueue *first_free; /* first free siginfo queue entry */
     int signal_pending; /* non zero if a signal may be pending */
 
     uint8_t stack[0];
@@ -186,12 +186,19 @@ extern int do_strace;
 /* signal.c */
 void process_pending_signals(CPUArchState *cpu_env);
 void signal_init(void);
-//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
-//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
-//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
-long do_sigreturn(CPUArchState *env);
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
+long do_sigreturn(CPUArchState *env, abi_ulong addr);
 long do_rt_sigreturn(CPUArchState *env);
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+int do_sigaction(int sig, const struct target_sigaction *act,
+                struct target_sigaction *oact);
+void QEMU_NORETURN force_sig(int target_sig);
 
 /* mmap.c */
 int target_mprotect(abi_ulong start, abi_ulong len, int prot);
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index e75fd0b..eb452fc 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -2,6 +2,7 @@
  *  Emulation of BSD signals
  *
  *  Copyright (c) 2003 - 2008 Fabrice Bellard
+ *  Copyright (c) 2013 Stacey Son
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -23,15 +24,936 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include "qemu.h"
 
 //#define DEBUG_SIGNAL
 
+static target_stack_t target_sigaltstack_used = {
+    .ss_sp = 0,
+    .ss_size = 0,
+    .ss_flags = TARGET_SS_DISABLE,
+};
+
+static uint8_t host_to_target_signal_table[TARGET_NSIG] = {
+    [SIGHUP]    =   TARGET_SIGHUP,
+    [SIGINT]    =   TARGET_SIGINT,
+    [SIGQUIT]   =   TARGET_SIGQUIT,
+    [SIGILL]    =   TARGET_SIGILL,
+    [SIGTRAP]   =   TARGET_SIGTRAP,
+    [SIGABRT]   =   TARGET_SIGABRT,
+    [SIGEMT]    =   TARGET_SIGEMT,
+    [SIGFPE]    =   TARGET_SIGFPE,
+    [SIGKILL]   =   TARGET_SIGKILL,
+    [SIGBUS]    =   TARGET_SIGBUS,
+    [SIGSEGV]   =   TARGET_SIGSEGV,
+    [SIGSYS]    =   TARGET_SIGSYS,
+    [SIGPIPE]   =   TARGET_SIGPIPE,
+    [SIGALRM]   =   TARGET_SIGALRM,
+    [SIGTERM]   =   TARGET_SIGTERM,
+    [SIGURG]    =   TARGET_SIGURG,
+    [SIGSTOP]   =   TARGET_SIGSTOP,
+    [SIGTSTP]   =   TARGET_SIGTSTP,
+    [SIGCONT]   =   TARGET_SIGCONT,
+    [SIGCHLD]   =   TARGET_SIGCHLD,
+    [SIGTTIN]   =   TARGET_SIGTTIN,
+    [SIGTTOU]   =   TARGET_SIGTTOU,
+    [SIGIO]     =   TARGET_SIGIO,
+    [SIGXCPU]   =   TARGET_SIGXCPU,
+    [SIGXFSZ]   =   TARGET_SIGXFSZ,
+    [SIGVTALRM] =   TARGET_SIGVTALRM,
+    [SIGPROF]   =   TARGET_SIGPROF,
+    [SIGWINCH]  =   TARGET_SIGWINCH,
+    [SIGINFO]   =   TARGET_SIGINFO,
+    [SIGUSR1]   =   TARGET_SIGUSR1,
+    [SIGUSR2]   =   TARGET_SIGUSR2,
+#ifdef SIGTHR
+    [SIGTHR + 3]    =   TARGET_SIGTHR,
+#endif
+    /* [SIGLWP] =   TARGET_SIGLWP, */
+#ifdef SIGLIBRT
+    [SIGLIBRT]  =   TARGET_SIGLIBRT,
+#endif
+
+    /*
+     * The following signals stay the same.
+     * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
+     * host libpthread signals.  This assumes no one actually uses
+     * SIGRTMAX.  To fix this properly we need to manual signal delivery
+     * multiplexed over a single host signal.
+     */
+    [SIGRTMIN]  =   SIGRTMAX,
+    [SIGRTMAX]  =   SIGRTMIN,
+};
+
+static uint8_t target_to_host_signal_table[TARGET_NSIG];
+static struct target_sigaction sigact_table[TARGET_NSIG];
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc);
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s);
+
+static inline int on_sig_stack(unsigned long sp)
+{
+    return sp - target_sigaltstack_used.ss_sp < 
target_sigaltstack_used.ss_size;
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+    return target_sigaltstack_used.ss_size == 0 ? SS_DISABLE : on_sig_stack(sp)
+        ? SS_ONSTACK : 0;
+}
+
+int host_to_target_signal(int sig)
+{
+
+    if (sig < 0 || sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return host_to_target_signal_table[sig];
+}
+
+int target_to_host_signal(int sig)
+{
+
+    if (sig >= TARGET_NSIG) {
+        return sig;
+    }
+
+    return target_to_host_signal_table[sig];
+}
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+
+    memset(set, 0, sizeof(*set));
+}
+
+static inline void target_sigaddset(target_sigset_t *set, int signum)
+{
+
+    signum--;
+    uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW);
+    set->__bits[signum / TARGET_NSIG_BPW] |= mask;
+}
+
+static inline int target_sigismember(const target_sigset_t *set, int signum)
+{
+
+    signum--;
+    abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
+    return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0;
+}
+
+static void host_to_target_sigset_internal(target_sigset_t *d,
+        const sigset_t *s)
+{
+    int i;
+
+    target_sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (sigismember(s, i)) {
+            target_sigaddset(d, host_to_target_signal(i));
+        }
+    }
+}
+
+void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
+{
+    target_sigset_t d1;
+    int i;
+
+    host_to_target_sigset_internal(&d1, s);
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        d->__bits[i] = tswap32(d1.__bits[i]);
+    }
+}
+
+static void target_to_host_sigset_internal(sigset_t *d,
+        const target_sigset_t *s)
+{
+    int i;
+
+    sigemptyset(d);
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        if (target_sigismember(s, i)) {
+            sigaddset(d, target_to_host_signal(i));
+        }
+    }
+}
+
+void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
+{
+    target_sigset_t s1;
+    int i;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        s1.__bits[i] = tswap32(s->__bits[i]);
+    }
+    target_to_host_sigset_internal(d, &s1);
+}
+
+/* Siginfo conversion. */
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
+        const siginfo_t *info)
+{
+    int sig, code;
+
+    sig = host_to_target_signal(info->si_signo);
+    /* XXX should have host_to_target_si_code() */
+    code = tswap32(info->si_code);
+    tinfo->si_signo = sig;
+    tinfo->si_errno = info->si_errno;
+    tinfo->si_code = info->si_code;
+    tinfo->si_pid = info->si_pid;
+    tinfo->si_uid = info->si_uid;
+    tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr;
+    /* si_value is opaque to kernel */
+    tinfo->si_value.sival_ptr =
+        (abi_ulong)(unsigned long)info->si_value.sival_ptr;
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = info->_reason._fault._trapno;
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = info->_reason._poll._band;
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = info->_reason._timer._timerid;
+        tinfo->_reason._timer._overrun = info->_reason._timer._overrun;
+    }
+}
+
+static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t 
*info)
+{
+    int sig, code;
+
+    sig = info->si_signo;
+    code = info->si_code;
+    tinfo->si_signo = tswap32(sig);
+    tinfo->si_errno = tswap32(info->si_errno);
+    tinfo->si_code = tswap32(info->si_code);
+    tinfo->si_pid = tswap32(info->si_pid);
+    tinfo->si_uid = tswap32(info->si_uid);
+    tinfo->si_addr = tswapal(info->si_addr);
+    if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig ||
+            SIGTRAP == sig) {
+        tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno);
+    }
+#ifdef SIGPOLL
+    if (SIGPOLL == sig) {
+        tinfo->_reason._poll._band = tswap32(info->_reason._poll._band);
+    }
+#endif
+    if (SI_TIMER == code) {
+        tinfo->_reason._timer._timerid = 
tswap32(info->_reason._timer._timerid);
+        tinfo->_reason._timer._overrun = 
tswap32(info->_reason._timer._overrun);
+    }
+}
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+    host_to_target_siginfo_noswap(tinfo, info);
+    tswap_siginfo(tinfo, tinfo);
+}
+
+#if 0 /* not yet */
+/* Returns 1 if given signal should dump core if not handled. */
+static int core_dump_signal(int sig)
+{
+    switch (sig) {
+    case TARGET_SIGABRT:
+    case TARGET_SIGFPE:
+    case TARGET_SIGILL:
+    case TARGET_SIGQUIT:
+    case TARGET_SIGSEGV:
+    case TARGET_SIGTRAP:
+    case TARGET_SIGBUS:
+        return 1;
+    default:
+        return 0;
+    }
+}
+#endif /* not yet */
+
+/* Signal queue handling. */
+static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env)
+{
+    TaskState *ts = env->opaque;
+    struct qemu_sigqueue *q = ts->first_free;
+
+    if (!q) {
+        return NULL;
+    }
+    ts->first_free = q->next;
+    return q;
+}
+
+static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q)
+{
+
+    TaskState *ts = env->opaque;
+    q->next = ts->first_free;
+    ts->first_free = q;
+}
+
+/* Abort execution with signal. */
+void QEMU_NORETURN force_sig(int target_sig)
+{
+#if 0 /* not yet */
+    TaskState *ts = (TaskState *)thread_env->opaque;
+    int core_dumped = 0;
+#endif
+    int host_sig;
+    struct sigaction act;
+
+    host_sig = target_to_host_signal(target_sig);
+    gdb_signalled(thread_env, target_sig);
+
+    /* Dump core if supported by target binary format */
+#if 0 /* net yet */
+    if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
+        stop_all_tasks();
+        core_dumped =
+            ((*ts->bprm->core_dump)(target_sig, thread_env) == 0);
+    }
+    if (core_dumped) {
+        struct rlimit nodump;
+
+        /*
+         * We already dumped the core of target process, we don't want
+         * a coredump of qemu itself.
+         */
+         getrlimit(RLIMIT_CORE, &nodump);
+         nodump.rlim_cur = 0;
+         (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) "
+             "- %s\n", target_sig, strsignal(host_sig), "core dumped");
+    }
+#endif /* not yet */
+
+    /*
+     * The proper exit code for dying from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive.
+     */
+    memset(&act, 0, sizeof(act));
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    kill(getpid(), host_sig);
+
+    /*
+     * Make sure the signal isn't masked (just reuse the mask inside
+     * of act).
+     */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    abort();
+}
+
+/*
+ * Queue a signal so that it will be send to the virtual CPU as soon as
+ * possible.
+ */
+int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
+{
+    TaskState *ts = env->opaque;
+    struct emulated_sigtable *k;
+    struct qemu_sigqueue *q, **pq;
+    abi_ulong handler;
+    int queue;
+
+    k = &ts->sigtab[sig - 1];
+    queue = gdb_queuesig();
+    handler = sigact_table[sig - 1]._sa_handler;
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig,
+        handler, (uint32_t)sigact_table[sig - 1].sa_flags);
+#endif
+    if (!queue && (TARGET_SIG_DFL == handler)) {
+        if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN ||
+            sig == TARGET_SIGTTOU) {
+            kill(getpid(), SIGSTOP);
+            return 0;
+        } else {
+            if (sig != TARGET_SIGCHLD &&
+                sig != TARGET_SIGURG &&
+                sig != TARGET_SIGWINCH &&
+                sig != TARGET_SIGCONT) {
+                force_sig(sig);
+            } else {
+                return 0; /* The signal was ignored. */
+            }
+        }
+    } else if (!queue && (TARGET_SIG_IGN == handler)) {
+        return 0; /* Ignored signal. */
+    } else if (!queue && (TARGET_SIG_ERR == handler)) {
+        force_sig(sig);
+    } else {
+        pq = &k->first;
+
+        /*
+         * FreeBSD signals are always queued.
+         * Linux only queues real time signals.
+         * XXX this code is not thread safe.
+         */
+        if (!k->pending) {
+            /* first signal */
+            q = &k->info;
+        } else {
+            q = alloc_sigqueue(env);
+            if (!q) {
+                return -EAGAIN;
+            }
+            while (*pq != NULL) {
+                pq = &(*pq)->next;
+            }
+        }
+        *pq = q;
+        q->info = *info;
+        q->next = NULL;
+        k->pending = 1;
+        /* Signal that a new signal is pending. */
+        ts->signal_pending = 1;
+        return 1; /* Indicates that the signal was queued. */
+    }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info, void *puc)
+{
+    int sig;
+    target_siginfo_t tinfo;
+
+    /*
+     * The CPU emulator uses some host signal to detect exceptions so
+     * we forward to it some signals.
+     */
+    if ((host_signum == SIGSEGV || host_signum == SIGBUS) &&
+            info->si_code < 0x10000) {
+        if (cpu_signal_handler(host_signum, info, puc)) {
+            return;
+        }
+    }
+
+    /* Get the target signal number. */
+    sig = host_to_target_signal(host_signum);
+    if (sig < 1 || sig > TARGET_NSIG) {
+        return;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+    host_to_target_siginfo_noswap(&tinfo, info);
+    if (queue_signal(thread_env, sig, &tinfo) == 1) {
+        /* Interrupt the virtual CPU as soon as possible. */
+        cpu_exit(thread_env);
+    }
+}
+
+/* do_sigaltstack() returns target values and errnos.  */
+/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+{
+    int ret = 0;
+    target_stack_t ss, oss, *uss;
+
+    if (uoss_addr) {
+        /* Save current signal stack params */
+        oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp);
+        oss.ss_size = tswapl(target_sigaltstack_used.ss_size);
+        oss.ss_flags = tswapl(sas_ss_flags(sp));
+    }
+
+    if (uss_addr) {
+
+        if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) ||
+            __get_user(ss.ss_sp, &uss->ss_sp) ||
+            __get_user(ss.ss_size, &uss->ss_size) ||
+            __get_user(ss.ss_flags, &uss->ss_flags)) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+        unlock_user_struct(uss, uss_addr, 0);
+
+        if (on_sig_stack(sp)) {
+            ret = -TARGET_EPERM;
+            goto out;
+        }
+
+        if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) {
+            ret = -TARGET_EINVAL;
+            goto out;
+        }
+
+        if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) {
+            if (ss.ss_size < TARGET_MINSIGSTKSZ) {
+                ret = -TARGET_ENOMEM;
+                goto out;
+            }
+        } else {
+            ss.ss_size = 0;
+            ss.ss_sp = 0;
+        }
+
+        target_sigaltstack_used.ss_sp = ss.ss_sp;
+        target_sigaltstack_used.ss_size = ss.ss_size;
+    }
+
+    if (uoss_addr) {
+        /* Copy out to user saved signal stack params */
+        if (copy_to_user(uoss_addr, &oss, sizeof(oss))) {
+            ret = -TARGET_EFAULT;
+            goto out;
+        }
+    }
+
+out:
+    return ret;
+}
+
+static int fatal_signal(int sig)
+{
+
+    switch (sig) {
+    case TARGET_SIGCHLD:
+    case TARGET_SIGURG:
+    case TARGET_SIGWINCH:
+        /* Ignored by default. */
+        return 0;
+    case TARGET_SIGCONT:
+    case TARGET_SIGSTOP:
+    case TARGET_SIGTSTP:
+    case TARGET_SIGTTIN:
+    case TARGET_SIGTTOU:
+        /* Job control signals.  */
+        return 0;
+    default:
+        return 1;
+    }
+}
+
+/* do_sigaction() return host values and errnos */
+int do_sigaction(int sig, const struct target_sigaction *act,
+        struct target_sigaction *oact)
+{
+    struct target_sigaction *k;
+    struct sigaction act1;
+    int host_sig;
+    int ret = 0;
+
+    if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig ||
+            TARGET_SIGSTOP == sig) {
+        return -EINVAL;
+    }
+    k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n",
+        sig, act, oact);
+#endif
+    if (oact) {
+        oact->_sa_handler = tswapal(k->_sa_handler);
+        oact->sa_flags = tswap32(k->sa_flags);
+        oact->sa_mask = k->sa_mask;
+    }
+    if (act) {
+        /* XXX: this is most likely not threadsafe. */
+        k->_sa_handler = tswapal(act->_sa_handler);
+        k->sa_flags = tswap32(act->sa_flags);
+        k->sa_mask = act->sa_mask;
+
+        /* Update the host signal state. */
+        host_sig = target_to_host_signal(sig);
+        if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+            memset(&act1, 0, sizeof(struct sigaction));
+            sigfillset(&act1.sa_mask);
+            if (k->sa_flags & TARGET_SA_RESTART) {
+                act1.sa_flags |= SA_RESTART;
+            }
+            /*
+             *  Note: It is important to update the host kernel signal mask to
+             *  avoid getting unexpected interrupted system calls.
+             */
+            if (k->_sa_handler == TARGET_SIG_IGN) {
+                act1.sa_sigaction = (void *)SIG_IGN;
+            } else if (k->_sa_handler == TARGET_SIG_DFL) {
+                if (fatal_signal(sig)) {
+                    act1.sa_flags = SA_SIGINFO;
+                    act1.sa_sigaction = host_signal_handler;
+                } else {
+                    act1.sa_sigaction = (void *)SIG_DFL;
+                }
+            } else {
+                act1.sa_flags = SA_SIGINFO;
+                act1.sa_sigaction = host_signal_handler;
+            }
+            ret = sigaction(host_sig, &act1, NULL);
+#if defined(DEBUG_SIGNAL)
+            fprintf(stderr, "sigaction (action = %p "
+                    "(host_signal_handler = %p)) returned: %d\n",
+                    act1.sa_sigaction, host_signal_handler, ret);
+#endif
+        }
+    }
+    return ret;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+        CPUArchState *regs, size_t frame_size)
+{
+    abi_ulong sp;
+
+    /* Use default user stack */
+    sp = get_sp_from_cpustate(regs);
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp +
+            target_sigaltstack_used.ss_size;
+    }
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+    return (sp - frame_size) & ~7;
+#else
+    return sp - frame_size;
+#endif
+}
+
+#if defined(TARGET_MIPS) || defined(TARGET_ARM)
+/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+    target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "setup_frame()\n");
+#endif
+#if defined(TARGET_SPARC64)
+    if (!sparc_user_sigtramp) {
+        /* No signal trampoline... kill the process. */
+        fprintf(stderr, "setup_frame(): no sigtramp\n");
+        force_sig(TARGET_SIGKILL);
+    }
+#endif
+
+    frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    memset(frame, 0, sizeof(*frame));
+#if defined(TARGET_MIPS)
+    int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC :
+        TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC;
+#else
+    int mflags = 0;
+#endif
+    if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) {
+        goto give_sigsegv;
+    }
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) {
+            goto give_sigsegv;
+        }
+    }
+
+    if (tinfo) {
+        frame->sf_si.si_signo = tinfo->si_signo;
+        frame->sf_si.si_errno = tinfo->si_errno;
+        frame->sf_si.si_code = tinfo->si_code;
+        frame->sf_si.si_pid = tinfo->si_pid;
+        frame->sf_si.si_uid = tinfo->si_uid;
+        frame->sf_si.si_status = tinfo->si_status;
+        frame->sf_si.si_addr = tinfo->si_addr;
+
+        if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig ||
+                TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig ||
+                TARGET_SIGTRAP == sig) {
+            frame->sf_si._reason._fault._trapno = 
tinfo->_reason._fault._trapno;
+        }
+
+        /*
+         * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or
+         * SI_MESGQ, then si_value contains the application-specified
+         * signal value. Otherwise, the contents of si_value are
+         * undefined.
+         */
+        if (SI_QUEUE == code || SI_TIMER == code || SI_ASYNCIO == code ||
+                SI_MESGQ == code) {
+            frame->sf_si.si_value.sival_int = tinfo->si_value.sival_int;
+        }
+
+        if (SI_TIMER == code) {
+            frame->sf_si._reason._timer._timerid =
+                tinfo->_reason._timer._timerid;
+            frame->sf_si._reason._timer._overrun =
+                tinfo->_reason._timer._overrun;
+        }
+
+#ifdef SIGPOLL
+        if (SIGPOLL == sig) {
+            frame->sf_si._reason._band = tinfo->_reason._band;
+        }
+#endif
+
+    }
+
+    if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) {
+        goto give_sigsegv;
+    }
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(TARGET_SIGSEGV);
+}
+
+#else
+
+static void setup_frame(int sig, int code, struct target_sigaction *ka,
+        target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *env)
+{
+
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+#endif /* !TARGET_MIPS */
+
+static int reset_signal_mask(target_ucontext_t *ucontext)
+{
+    int i;
+    sigset_t blocked;
+    target_sigset_t target_set;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++)
+        if (__get_user(target_set.__bits[i],
+                    &ucontext->uc_sigmask.__bits[i])) {
+            return -TARGET_EFAULT;
+        }
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    return 0;
+}
+
+long do_sigreturn(CPUArchState *regs, abi_ulong addr)
+{
+    target_ucontext_t *ucontext;
+
+    /* Lock the memory and get the ucontext ptr from the stack frame */
+    if (!lock_user_struct(VERIFY_READ, ucontext,  addr, 0)) {
+            goto badframe;
+    }
+
+    /* Set the register state back to before the signal. */
+    if (set_mcontext(regs, &ucontext->uc_mcontext, 1)) {
+        goto badframe;
+    }
+
+    /* And reset the signal mask. */
+    if (reset_signal_mask(ucontext)) {
+        goto badframe;
+    }
+
+    unlock_user_struct(ucontext, addr, 0);
+    return -TARGET_EJUSTRETURN;
+
+badframe:
+    if (addr != 0) {
+        unlock_user_struct(ucontext, addr, 0);
+    }
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_EFAULT;
+}
+
 void signal_init(void)
 {
+    struct sigaction act;
+    struct sigaction oact;
+    int i, j;
+    int host_sig;
+
+    /* Generate the signal conversion tables.  */
+    for (i = 1; i < TARGET_NSIG; i++) {
+        if (host_to_target_signal_table[i] == 0) {
+            host_to_target_signal_table[i] = i;
+        }
+    }
+    for (i = 1; i < TARGET_NSIG; i++) {
+        j = host_to_target_signal_table[i];
+        target_to_host_signal_table[j] = i;
+    }
+
+    /*
+     * Set all host signal handlers. ALL signals are blocked during the
+     * handlers to serialize them.
+     */
+    memset(sigact_table, 0, sizeof(sigact_table));
+
+    sigfillset(&act.sa_mask);
+    act.sa_sigaction = host_signal_handler;
+    act.sa_flags = SA_SIGINFO;
+
+    for (i = 1; i <= TARGET_NSIG; i++) {
+        host_sig = target_to_host_signal(i);
+        sigaction(host_sig, NULL, &oact);
+        if (oact.sa_sigaction == (void *)SIG_IGN) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
+        } else if (oact.sa_sigaction == (void *)SIG_DFL) {
+            sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
+        }
+        /*
+         * If there's already a handler installed then something has
+         * gone horribly wrong, so don't even try to handle that case.
+         * Install some handlers for our own use.  We need at least
+         * SIGSEGV and SIGBUS, to detect exceptions.  We can not just
+         * trap all signals because it affects syscall interrupt
+         * behavior.  But do trap all default-fatal signals.
+         */
+        if (fatal_signal(i)) {
+            sigaction(host_sig, &act, NULL);
+        }
+    }
 }
 
 void process_pending_signals(CPUArchState *cpu_env)
 {
+    int sig, code;
+    abi_ulong handler;
+    sigset_t set, old_set;
+    target_sigset_t target_old_set;
+    target_siginfo_t tinfo;
+    struct emulated_sigtable *k;
+    struct target_sigaction *sa;
+    struct qemu_sigqueue *q;
+    TaskState *ts = cpu_env->opaque;
+
+    if (!ts->signal_pending) {
+        return;
+    }
+
+    /* FIXME: This is not threadsafe.  */
+    k  = ts->sigtab;
+    for (sig = 1; sig <= TARGET_NSIG; sig++) {
+        if (k->pending) {
+            goto handle_signal;
+        }
+        k++;
+    }
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process_pending_signals has no signals\n");
+#endif
+    /* If no signal is pending then just return. */
+    ts->signal_pending = 0;
+    return;
+
+handle_signal:
+#ifdef DEBUG_SIGNAL
+    fprintf(stderr, "qemu: process signal %d\n", sig);
+#endif
+
+    /* Dequeue signal. */
+    q = k->first;
+    k->first = q->next;
+    if (!k->first) {
+        k->pending = 0;
+    }
+
+    sig = gdb_handlesig(cpu_env, sig);
+    if (!sig) {
+        sa = NULL;
+        handler = TARGET_SIG_IGN;
+    } else {
+        sa = &sigact_table[sig - 1];
+        handler = sa->_sa_handler;
+    }
+
+    if (handler == TARGET_SIG_DFL) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_DFL\n");
+#endif
+        /*
+         * default handler : ignore some signal. The other are job
+         * control or fatal.
+         */
+        if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig ||
+                TARGET_SIGTTOU == sig) {
+            kill(getpid(), SIGSTOP);
+        } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig &&
+            TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) {
+            force_sig(sig);
+        }
+    } else if (TARGET_SIG_IGN == handler) {
+        /* ignore sig */
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_IGN\n");
+#endif
+    } else if (TARGET_SIG_ERR == handler) {
+#ifdef DEBUG_SIGNAL
+        fprintf(stderr, "qemu: TARGET_SIG_ERR\n");
+#endif
+        force_sig(sig);
+    } else {
+        /* compute the blocked signals during the handler execution */
+        target_to_host_sigset(&set, &sa->sa_mask);
+        /*
+         * SA_NODEFER indicates that the current signal should not be
+         * blocked during the handler.
+         */
+        if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+            sigaddset(&set, target_to_host_signal(sig));
+        }
+
+        /* block signals in the handler */
+        sigprocmask(SIG_BLOCK, &set, &old_set);
+
+        /*
+         * Save the previous blocked signal state to restore it at the
+         * end of the signal execution (see do_sigreturn).
+         */
+        host_to_target_sigset_internal(&target_old_set, &old_set);
+
+#if 0  /* not yet */
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+        /* if the CPU is in VM86 mode, we restore the 32 bit values */
+        {
+            CPUX86State *env = cpu_env;
+            if (env->eflags & VM_MASK) {
+                save_v86_state(env);
+            }
+        }
+#endif
+#endif /* not yet */
+
+        code = q->info.si_code;
+        /* prepare the stack frame of the virtual CPU */
+        if (sa->sa_flags & TARGET_SA_SIGINFO) {
+            tswap_siginfo(&tinfo, &q->info);
+            setup_frame(sig, code, sa, &target_old_set, &tinfo, cpu_env);
+        } else {
+            setup_frame(sig, code, sa, &target_old_set, NULL, cpu_env);
+        }
+        if (sa->sa_flags & TARGET_SA_RESETHAND) {
+            sa->_sa_handler = TARGET_SIG_DFL;
+        }
+    }
+    if (q != &k->info) {
+        free_sigqueue(cpu_env, q);
+    }
 }
diff --git a/bsd-user/sparc/target_arch_signal.h 
b/bsd-user/sparc/target_arch_signal.h
index 6bef0ad..275d1ef 100644
--- a/bsd-user/sparc/target_arch_signal.h
+++ b/bsd-user/sparc/target_arch_signal.h
@@ -3,4 +3,43 @@
 
 #include "cpu.h"
 
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE   (0) */       /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    return -TARGET_EOPNOTSUPP;
+}
+
 #endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/sparc64/target_arch_signal.h 
b/bsd-user/sparc64/target_arch_signal.h
index eb7ad2a..8126383 100644
--- a/bsd-user/sparc64/target_arch_signal.h
+++ b/bsd-user/sparc64/target_arch_signal.h
@@ -20,4 +20,43 @@
 
 #include "cpu.h"
 
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */      /* XXX to be added. */
+
+/* compare to  sparc64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (1024 * 4)              /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUSPARCState *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    return -TARGET_EOPNOTSUPP;
+}
+
 #endif /* !_TARGET_ARCH_SIGNAL_H_ */
diff --git a/bsd-user/x86_64/target_arch_signal.h 
b/bsd-user/x86_64/target_arch_signal.h
index 614c11a..d43f5f0 100644
--- a/bsd-user/x86_64/target_arch_signal.h
+++ b/bsd-user/x86_64/target_arch_signal.h
@@ -20,4 +20,43 @@
 
 #include "cpu.h"
 
+/* Size of the signal trampolin code placed on the stack. */
+/* #define TARGET_SZSIGCODE    (0) */   /* XXX to be added */
+
+/* compare to  x86/include/_limits.h */
+#define TARGET_MINSIGSTKSZ  (512 * 4)               /* min sig stack size */
+#define TARGET_SIGSTKSZ     (MINSIGSTKSZ + 32768)   /* recommended size */
+
+struct target_sigcontext {
+    /* to be added */
+};
+
+typedef struct target_mcontext {
+} target_mcontext_t;
+
+typedef struct target_ucontext {
+    target_sigset_t   uc_sigmask;
+    target_mcontext_t uc_mcontext;
+    abi_ulong         uc_link;
+    target_stack_t    uc_stack;
+    int32_t           uc_flags;
+    int32_t         __spare__[4];
+} target_ucontext_t;
+
+struct target_sigframe {
+    abi_ulong   sf_signum;
+    abi_ulong   sf_siginfo;    /* code or pointer to sf_si */
+    abi_ulong   sf_ucontext;   /* points to sf_uc */
+    abi_ulong   sf_addr;       /* undocumented 4th arg */
+    target_ucontext_t   sf_uc; /* = *sf_uncontext */
+    target_siginfo_t    sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+    uint32_t    __spare__[2];
+};
+
+static inline abi_long set_mcontext(CPUX86State *regs,
+        target_mcontext_t *mcp, int srflag)
+{
+    return -TARGET_EOPNOTSUPP;
+}
+
 #endif /* !TARGET_ARCH_SIGNAL_H_ */
-- 
1.7.8




reply via email to

[Prev in Thread] Current Thread [Next in Thread]