summaryrefslogtreecommitdiff
path: root/emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c
diff options
context:
space:
mode:
authorJuergen Lock <nox@FreeBSD.org>2013-03-29 17:40:38 +0000
committerJuergen Lock <nox@FreeBSD.org>2013-03-29 17:40:38 +0000
commit45aa9370f03dfaf05a98af04f0addd7e3998d771 (patch)
treed33294058708ce0ec0faa156a7ed184dea6cdc1d /emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c
parent- (force commit to note) add new port: games/chessx (diff)
- Update net/usbredir to 0.6 .
- Update emulators/qemu-devel to 1.4.0 with preliminary bsd-user patches. Thanx to: sson, cognet, and others for much improved bsd-user support - it now runs at least quite a few mips64 and single-threaded arm binaries, see: https://wiki.freebsd.org/QemuUserModeHowTo
Diffstat (limited to 'emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c')
-rw-r--r--emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c2301
1 files changed, 2301 insertions, 0 deletions
diff --git a/emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c b/emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c
new file mode 100644
index 000000000000..e0f024151e70
--- /dev/null
+++ b/emulators/qemu-devel/files/patch-z2c-bsd-user-sson-002c
@@ -0,0 +1,2301 @@
+diff --git a/bsd-user/arm/target_signal.h b/bsd-user/arm/target_signal.h
+index 19cc188..6b7bb67 100644
+--- a/bsd-user/arm/target_signal.h
++++ b/bsd-user/arm/target_signal.h
+@@ -11,4 +11,29 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+ #define TARGET_MINSIGSTKSZ (1024 * 4)
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
++typedef target_ulong target_mcontext_t; /* dummy */
++
++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;
++
++static inline int
++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "ARM doesn't have support for get_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
++static inline int
++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "ARM doesn't have support for set_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
+ #endif /* TARGET_SIGNAL_H */
+diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list
+index 1edf412..b09f766 100644
+--- a/bsd-user/freebsd/strace.list
++++ b/bsd-user/freebsd/strace.list
+@@ -38,6 +38,7 @@
+ { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_getcontext, "getcontext", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
+@@ -123,6 +124,7 @@
+ { TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_setcontext, "setcontext", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL },
+@@ -160,6 +162,15 @@
+ { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_kill, "thr_kill", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_kill2, "thr_kill2", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_new, "thr_new", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_self, "thr_self", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_set_name, "thr_set_name", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_suspend, "thr_suspend", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR_thr_wake, "thr_wake", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL },
+ { TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL },
+diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h
+index 285e7f9..28481ce 100644
+--- a/bsd-user/i386/target_signal.h
++++ b/bsd-user/i386/target_signal.h
+@@ -11,4 +11,29 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+ #define TARGET_MINSIGSTKSZ (512 * 4)
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
++typedef target_ulong target_mcontext_t; /* dummy */
++
++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;
++
++static inline int
++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "i386 doesn't have support for get_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
++static inline int
++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "i386 doesn't have support for set_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
+ #endif /* TARGET_SIGNAL_H */
+diff --git a/bsd-user/main.c b/bsd-user/main.c
+index 146f022..7a99537 100644
+--- a/bsd-user/main.c
++++ b/bsd-user/main.c
+@@ -34,6 +34,10 @@
+ #include "qemu-timer.h"
+ #include "envlist.h"
+
++#if defined(CONFIG_USE_NPTL) && defined(__FreeBSD__)
++#include <sys/thr.h>
++#endif
++
+ #define DEBUG_LOGFILE "/tmp/qemu.log"
+
+ int singlestep;
+@@ -70,42 +74,186 @@ int cpu_get_pic_interrupt(CPUX86State *env)
+ }
+ #endif
+
+-/* These are no-ops because we are not threadsafe. */
+-static inline void cpu_exec_start(CPUArchState *env)
++#if defined(CONFIG_USE_NPTL)
++/* Helper routines for implementing atomic operations. */
++
++/*
++ * To implement exclusive operations we force all cpus to synchronize.
++ * We don't require a full sync, only that no cpus are executing guest code.
++ * The alternative is to map target atomic ops onto host eqivalents,
++ * which requires quite a lot of per host/target work.
++ */
++static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
++static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
++static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
++static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
++static int pending_cpus;
++
++/* Make sure everything is in a consistent state for calling fork(). */
++void fork_start(void)
+ {
++ pthread_mutex_lock(&tb_lock);
++ pthread_mutex_lock(&exclusive_lock);
++ mmap_fork_start();
+ }
+
+-static inline void cpu_exec_end(CPUArchState *env)
++void fork_end(int child)
+ {
++ mmap_fork_end(child);
++ if (child) {
++ /*
++ * Child processes created by fork() only have a single thread.
++ * Discard information about the parent threads.
++ */
++ first_cpu = thread_env;
++ thread_env->next_cpu = NULL;
++ pending_cpus = 0;
++ pthread_mutex_init(&exclusive_lock, NULL);
++ pthread_mutex_init(&cpu_list_mutex, NULL);
++ pthread_cond_init(&exclusive_cond, NULL);
++ pthread_cond_init(&exclusive_resume, NULL);
++ pthread_mutex_init(&tb_lock, NULL);
++ gdbserver_fork(thread_env);
++ } else {
++ pthread_mutex_unlock(&exclusive_lock);
++ pthread_mutex_unlock(&tb_lock);
++ }
+ }
+
+-static inline void start_exclusive(void)
++/*
++ * Wait for pending exclusive operations to complete. The exclusive lock
++ * must be held.
++ */
++static inline void
++exclusive_idle(void)
+ {
++ while (pending_cpus) {
++ pthread_cond_wait(&exclusive_resume, &exclusive_lock);
++ }
+ }
+
+-static inline void end_exclusive(void)
++/* Start an exclusive operation. Must only be called outside of cpu_exec. */
++static inline void
++start_exclusive(void)
+ {
++ CPUArchState *other;
++
++ pthread_mutex_lock(&exclusive_lock);
++ exclusive_idle();
++
++ pending_cpus = 1;
++ /* Make all other cpus stop executing. */
++ for (other = first_cpu; other; other = other->next_cpu) {
++ if (other->running) {
++ pending_cpus++;
++ cpu_exit(other);
++ }
++ }
++ if (pending_cpus > 1) {
++ pthread_cond_wait(&exclusive_cond, &exclusive_lock);
++ }
+ }
+
+-void fork_start(void)
++/* Finish an exclusive operation. */
++static inline void
++end_exclusive(void)
+ {
++ pending_cpus = 0;
++ pthread_cond_broadcast(&exclusive_resume);
++ pthread_mutex_unlock(&exclusive_lock);
+ }
+
+-void fork_end(int child)
++/* Wait for exclusive ops to finish, and begin cpu execution. */
++static inline void
++cpu_exec_start(CPUArchState *env)
++{
++ pthread_mutex_lock(&exclusive_lock);
++ exclusive_idle();
++ env->running = 1;
++ pthread_mutex_unlock(&exclusive_lock);
++}
++
++/* Mark cpu as not excuting, and release pending exclusive ops. */
++static inline void
++cpu_exec_end(CPUArchState *env)
++{
++ pthread_mutex_lock(&exclusive_lock);
++ env->running = 0;
++ if (pending_cpus > 1) {
++ pending_cpus--;
++ if (pending_cpus == 1) {
++ pthread_cond_signal(&exclusive_cond);
++ }
++ }
++ exclusive_idle();
++ pthread_mutex_unlock(&exclusive_lock);
++}
++
++void
++cpu_list_lock(void)
++{
++ pthread_mutex_lock(&cpu_list_mutex);
++}
++
++void
++cpu_list_unlock(void)
++{
++ pthread_mutex_unlock(&cpu_list_mutex);
++}
++
++#else /* ! CONFIG_USE_NPTL */
++
++/* These are no-ops because we are not threadsafe. */
++void
++fork_start(void)
++{
++}
++
++void
++fork_end(int child)
+ {
+ if (child) {
+ gdbserver_fork(thread_env);
+ }
+ }
+
+-void cpu_list_lock(void)
++static inline void
++exclusive_idle(void)
++{
++}
++
++static inline void
++start_exclusive(void)
+ {
+ }
+
+-void cpu_list_unlock(void)
++static inline void
++end_exclusive(void)
+ {
+ }
+
++static inline void
++cpu_exec_start(CPUArchState *env)
++{
++}
++
++
++static inline void
++cpu_exec_end(CPUArchState *env)
++{
++}
++
++void
++cpu_list_lock(void)
++{
++}
++
++void
++cpu_list_unlock(void)
++{
++}
++#endif /* CONFIG_USE_NPTL */
++
+ #ifdef TARGET_I386
+ /***********************************************************/
+ /* CPUX86 core interface */
+@@ -740,7 +888,10 @@ void cpu_loop(CPUMIPSState *env)
+
+ for(;;) {
+ cpu_exec_start(env);
++ /* XXX there is a concurrency problem - giant lock for now */
++ pthread_mutex_lock(&exclusive_lock); /* XXX */
+ trapnr = cpu_mips_exec(env);
++ pthread_mutex_unlock(&exclusive_lock); /* XXX */
+ cpu_exec_end(env);
+ switch(trapnr) {
+ case EXCP_SYSCALL: /* syscall exception */
+@@ -1206,6 +1357,18 @@ static void usage(void)
+
+ THREAD CPUArchState *thread_env;
+
++void task_settid(TaskState *ts)
++{
++ if (0 == ts->ts_tid) {
++#ifdef CONFIG_USE_NPTL
++ (void)thr_self(&ts->ts_tid);
++#else
++ /* When no threads then just use PID */
++ ts->ts_tid = getpid();
++#endif
++ }
++}
++
+ void stop_all_tasks(void)
+ {
+ /*
+diff --git a/bsd-user/mips/target_signal.h b/bsd-user/mips/target_signal.h
+index 28871c3..484cfd8 100644
+--- a/bsd-user/mips/target_signal.h
++++ b/bsd-user/mips/target_signal.h
+@@ -6,9 +6,187 @@
+ #define TARGET_MINSIGSTKSZ (512 * 4)
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
+-static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
++struct target_sigcontext {
++ target_sigset_t sc_mask; /* signal mask to retstore */
++ int32_t sc_onstack; /* sigstack state to restore */
++ abi_long sc_pc; /* pc at time of signal */
++ abi_long sc_reg[32]; /* processor regs 0 to 31 */
++ abi_long mullo, mulhi; /* mullo and mulhi registers */
++ int32_t sc_fpused; /* fp has been used */
++ abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */
++ abi_long sc_fpc_eir; /* fp exception instr reg */
++ /* int32_t reserved[8]; */
++};
++
++typedef struct target_mcontext {
++ int32_t mc_onstack; /* sigstack state to restore */
++ abi_long mc_pc; /* pc at time of signal */
++ abi_long mc_regs[32]; /* process regs 0 to 31 */
++ abi_long sr; /* status register */
++ abi_long mullo, mulhi;
++ int32_t mc_fpused; /* fp has been used */
++ abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */
++ abi_long mc_fpc_eir; /* fp exception instr reg */
++ abi_ulong mc_tls; /* pointer to TLS area */
++} 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];
++};
++
++
++/* Get the stack pointer. */
++static inline abi_ulong
++get_sp_from_cpustate(CPUMIPSState *state)
+ {
+ return state->active_tc.gpr[29];
+ }
+
++/*
++ * Compare to mips/mips/pm_machdep.c sendsig()
++ * Assumes that "frame" memory is locked.
++ */
++static inline int
++set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
++ abi_ulong frame_addr, struct target_sigaction *ka)
++{
++
++ frame->sf_signum = sig;
++ frame->sf_siginfo = 0;
++ frame->sf_ucontext = 0;
++
++ frame->sf_si.si_signo = sig;
++ frame->sf_si.si_code = TARGET_SA_SIGINFO;
++ frame->sf_si.si_addr = regs->CP0_BadVAddr;
++
++ /*
++ * 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[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 int
++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 int
++set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags)
++{
++ 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);
++
++ /* Don't do any of the status and cause registers. */
++
++ return (err);
++}
++
+ #endif /* TARGET_SIGNAL_H */
+diff --git a/bsd-user/mips64/target_signal.h b/bsd-user/mips64/target_signal.h
+index d671f4e..e9c8a9f 100644
+--- a/bsd-user/mips64/target_signal.h
++++ b/bsd-user/mips64/target_signal.h
+@@ -7,11 +7,186 @@
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+ #define TARGET_SZSIGCODE 16
+
+-#define TARGET_UCONTEXT_MAGIC 0xACEDBADE
++struct target_sigcontext {
++ target_sigset_t sc_mask; /* signal mask to retstore */
++ int32_t sc_onstack; /* sigstack state to restore */
++ abi_long sc_pc; /* pc at time of signal */
++ abi_long sc_reg[32]; /* processor regs 0 to 31 */
++ abi_long mullo, mulhi; /* mullo and mulhi registers */
++ int32_t sc_fpused; /* fp has been used */
++ abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */
++ abi_long sc_fpc_eir; /* fp exception instr reg */
++ /* int32_t reserved[8]; */
++};
+
+-static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
++typedef struct target_mcontext {
++ int32_t mc_onstack; /* sigstack state to restore */
++ abi_long mc_pc; /* pc at time of signal */
++ abi_long mc_regs[32]; /* process regs 0 to 31 */
++ abi_long sr; /* status register */
++ abi_long mullo, mulhi;
++ int32_t mc_fpused; /* fp has been used */
++ abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */
++ abi_long mc_fpc_eir; /* fp exception instr reg */
++ abi_ulong mc_tls; /* pointer to TLS area */
++} 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_ulong
++get_sp_from_cpustate(CPUMIPSState *state)
+ {
+ return state->active_tc.gpr[29];
+ }
+
++/*
++ * Compare to mips/mips/pm_machdep.c sendsig()
++ * Assumes that "frame" memory is locked.
++ */
++static inline int
++set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame,
++ abi_ulong frame_addr, struct target_sigaction *ka)
++{
++
++ frame->sf_signum = sig;
++ frame->sf_siginfo = 0;
++ frame->sf_ucontext = 0;
++
++ frame->sf_si.si_signo = sig;
++ frame->sf_si.si_code = TARGET_SA_SIGINFO;
++ frame->sf_si.si_addr = regs->CP0_BadVAddr;
++
++ /*
++ * 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[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 int
++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 int
++set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags)
++{
++ 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);
++
++ /* Don't do any of the status and cause registers. */
++
++ return (err);
++}
++
+ #endif /* TARGET_SIGNAL_H */
++
+diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
+--- a/bsd-user/mmap.c
++++ b/bsd-user/mmap.c
+@@ -74,6 +74,8 @@ void mmap_unlock(void)
+ }
+ #endif
+
++#if 0 /* XXX not sure why we need our own g_malloc() and friends.
++ g_strdup(), however, has serious problems with this g_malloc/g_free */
+ static void *bsd_vmalloc(size_t size)
+ {
+ void *p;
+@@ -133,6 +135,7 @@ void *g_realloc(void *ptr, size_t size)
+ g_free(ptr);
+ return new_ptr;
+ }
++#endif
+
+ /* NOTE: all the constants are the HOST ones, but addresses are target. */
+ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
+diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
+index ab7e18c..9d4edbf 100644
+--- a/bsd-user/qemu.h
++++ b/bsd-user/qemu.h
+@@ -80,7 +80,7 @@ struct emulated_sigtable {
+ typedef struct TaskState {
+ struct TaskState *next;
+ int used; /* non zero if used */
+-#if 1
++ long ts_tid; /* tid (or pid) of this task */
+ #ifdef TARGET_ARM
+ int swi_errno;
+ #endif
+@@ -90,7 +90,6 @@ typedef struct TaskState {
+ uint32_t heap_limit;
+ #endif
+ uint32_t stack_base;
+-#endif
+ struct image_info *info;
+ struct bsd_binprm *bprm;
+
+diff --git a/bsd-user/signal.c b/bsd-user/signal.c
+index 52441c4..d56837b 100644
+--- a/bsd-user/signal.c
++++ b/bsd-user/signal.c
+@@ -31,7 +31,7 @@
+ #include "qemu.h"
+ #include "target_signal.h"
+
+-//#define DEBUG_SIGNAL
++// #define DEBUG_SIGNAL
+
+ #ifndef _NSIG
+ #define _NSIG 128
+@@ -606,101 +606,31 @@ do_sigaction(int sig, const struct target_sigaction *act,
+ return (ret);
+ }
+
+-#if defined(TARGET_MIPS64)
+-static inline int
+-restore_sigmcontext(CPUMIPSState *regs, target_mcontext_t *mc)
+-{
+- int i, err = 0;
+-
+- for(i = 1; i < 32; i++)
+- err |= __get_user(regs->active_tc.gpr[i],
+- &mc->mc_regs[i]);
+- err |= __get_user(regs->CP0_EPC, &mc->mc_pc);
+- err |= __get_user(regs->active_tc.LO[0], &mc->mullo);
+- err |= __get_user(regs->active_tc.HI[0], &mc->mulhi);
+- err |= __get_user(regs->tls_value, &mc->mc_tls); /* XXX thread tls */
+-
+-#if 0 /* XXX */
+- int used_fp = 0;
+-
+- err |= __get_user(used_fp, &mc->mc_fpused);
+- conditional_used_math(used_fp);
+-
+- preempt_disabled();
+- if (used_math()) {
+- /* restore fpu context if we have used it before */
+- own_fpu();
+- err |= restore_fp_context(mc);
+- } else {
+- /* signal handler may have used FPU. Give it up. */
+- lose_fpu();
+- }
+- preempt_enable();
+-#endif
+-
+- return (err);
+-}
+-
+-static inline int
+-setup_sigmcontext(CPUMIPSState *regs, target_mcontext_t *mc, int32_t oonstack)
+-{
+- int i, err = 0;
+- abi_long ucontext_magic = TARGET_UCONTEXT_MAGIC;
+-
+- err = __put_user(oonstack ? 1 : 0, &mc->mc_onstack);
+- err |= __put_user(regs->active_tc.PC, &mc->mc_pc);
+- err |= __put_user(regs->active_tc.LO[0], &mc->mullo);
+- err |= __put_user(regs->active_tc.HI[0], &mc->mulhi);
+- err |= __put_user(regs->tls_value, &mc->mc_tls); /* XXX thread tls */
+-
+- err |= __put_user(ucontext_magic, &mc->mc_regs[0]);
+- for(i = 1; i < 32; i++)
+- err |= __put_user(regs->active_tc.gpr[i], &mc->mc_regs[i]);
+-
+- err |= __put_user(0, &mc->mc_fpused);
+-
+-#if 0 /* XXX */
+- err |= __put_user(used_math(), &mc->mc_fpused);
+- if (used_math())
+- goto out;
+-
+- /*
+- * Save FPU state to signal context. Signal handler will "inherit"
+- * current FPU state.
+- */
+- preempt_disable();
+-
+- if (!is_fpu_owner()) {
+- own_fpu();
+- for(i = 0; i < 33; i++)
+- err |= __put_user(regs->active_tc.fpregs[i], &mc->mc_fpregs[i]);
+- }
+- err |= save_fp_context(fg);
+-
+- preempt_enable();
+-out:
+-#endif
+- return (err);
+-}
++#if defined(TARGET_MIPS) || defined(TARGET_SPARC64)
+
+ static inline abi_ulong
+-get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
++get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size)
+ {
+ abi_ulong sp;
+
+ /* Use default user stack */
+- sp = regs->active_tc.gpr[29];
++ 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;
++ sp = target_sigaltstack_used.ss_sp +
++ target_sigaltstack_used.ss_size;
+ }
+
++#if defined(TARGET_MIPS)
+ return ((sp - frame_size) & ~7);
++#else
++ return (sp - frame_size);
++#endif
+ }
+
+-/* compare to mips/mips/pm_machdep.c sendsig() */
++/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */
+ static void setup_frame(int sig, struct target_sigaction *ka,
+- target_sigset_t *set, CPUMIPSState *regs)
++ target_sigset_t *set, CPUArchState *regs)
+ {
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+@@ -709,54 +639,36 @@ static void setup_frame(int sig, struct target_sigaction *ka,
+ #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;
+
+- if (setup_sigmcontext(regs, &frame->sf_uc.uc_mcontext,
+- ! on_sig_stack(frame_addr)))
++#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]))
++ if (__put_user(set->__bits[i],
++ &frame->sf_uc.uc_sigmask.__bits[i]))
+ goto give_sigsegv;
+ }
+
+- /* fill in sigframe structure */
+- if (__put_user(sig, &frame->sf_signum))
+- goto give_sigsegv;
+- if (__put_user(0, &frame->sf_siginfo))
+- goto give_sigsegv;
+- if (__put_user(0, &frame->sf_ucontext))
++ if (set_sigtramp_args(regs, sig, frame, frame_addr, ka))
+ goto give_sigsegv;
+
+- /* fill in siginfo structure */
+- if (__put_user(sig, &frame->sf_si.si_signo))
+- goto give_sigsegv;
+- if (__put_user(TARGET_SA_SIGINFO, &frame->sf_si.si_code))
+- goto give_sigsegv;
+- if (__put_user(regs->CP0_BadVAddr, &frame->sf_si.si_addr))
+- goto give_sigsegv;
+-
+- /*
+- * 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;
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+@@ -766,7 +678,7 @@ give_sigsegv:
+ }
+
+ long
+-do_sigreturn(CPUMIPSState *regs, abi_ulong uc_addr)
++do_sigreturn(CPUArchState *regs, abi_ulong uc_addr)
+ {
+ target_ucontext_t *ucontext;
+ sigset_t blocked;
+@@ -784,14 +696,17 @@ do_sigreturn(CPUMIPSState *regs, abi_ulong uc_addr)
+ goto badframe;
+ }
+
+- if (restore_sigmcontext(regs, &ucontext->uc_mcontext))
++ if (set_mcontext(regs, &ucontext->uc_mcontext, 0))
+ goto badframe;
+
+ target_to_host_sigset_internal(&blocked, &target_set);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+- regs->active_tc.PC = regs->CP0_EPC;
+- regs->CP0_EPC = 0; /* XXX for nested signals ? */
++#if defined(TARGET_MIPS)
++ CPUMIPSState *mips_regs = (CPUMIPSState *)regs;
++ mips_regs->active_tc.PC = mips_regs->CP0_EPC;
++ mips_regs->CP0_EPC = 0; /* XXX for nested signals ? */
++#endif
+ return (-TARGET_QEMU_ESIGRETURN);
+
+ badframe:
+@@ -799,9 +714,10 @@ badframe:
+ return (0);
+ }
+
+-#elif defined(TARGET_SPARC64)
+
+-extern abi_ulong sparc_user_sigtramp;
++
++/* #elif defined(TARGET_SPARC64) */
++#if 0
+
+ #define mc_flags mc_global[0]
+ #define mc_sp mc_out[6]
+@@ -1039,6 +955,7 @@ badframe:
+ force_sig(TARGET_SIGSEGV);
+ return (0);
+ }
++#endif
+
+ #else
+
+diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h
+index 79dfc1e..e2fe79c 100644
+--- a/bsd-user/sparc/target_signal.h
++++ b/bsd-user/sparc/target_signal.h
+@@ -13,9 +13,34 @@
+ #define TARGET_MINSIGSTKSZ (512 * 4)
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
++typedef target_ulong target_mcontext_t; /* dummy */
++
++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;
++
+ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
+ {
+ return state->regwptr[UREG_FP];
+ }
+
++static inline int
++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "SPARC doesn't have support for get_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
++static inline int
++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "SPARC doesn't have support for set_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
+ #endif /* TARGET_SIGNAL_H */
+diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h
+index d3e58bb..1bc7c96 100644
+--- a/bsd-user/sparc64/target_signal.h
++++ b/bsd-user/sparc64/target_signal.h
+@@ -10,12 +10,239 @@
+ #define UREG_FP UREG_I6
+ #endif
+
++#define mc_flags mc_global[0]
++#define mc_sp mc_out[6]
++#define mc_fprs mc_local[0]
++#define mc_fsr mc_local[1]
++#define mc_gsr mc_local[2]
++#define mc_tnpc mc_in[0]
++#define mc_tpc mc_in[1]
++#define mc_tstate mc_in[2]
++#define mc_y mc_in[4]
++#define mc_wstate mc_in[5]
++
++#define ureg_i0 regwptr[0 ]
++#define ureg_i1 regwptr[1 ]
++#define ureg_i2 regwptr[2 ]
++#define ureg_i3 regwptr[3 ]
++#define ureg_i4 regwptr[4 ]
++#define ureg_i5 regwptr[5 ]
++#define ureg_i6 regwptr[6 ]
++#define ureg_i7 regwptr[7 ]
++#define ureg_l0 regwptr[8 ]
++#define ureg_l1 regwptr[9 ]
++#define ureg_l2 regwptr[10]
++#define ureg_l3 regwptr[11]
++#define ureg_l4 regwptr[12]
++#define ureg_l5 regwptr[13]
++#define ureg_l6 regwptr[14]
++#define ureg_l7 regwptr[15]
++#define ureg_o0 regwptr[16]
++#define ureg_o1 regwptr[17]
++#define ureg_o2 regwptr[18]
++#define ureg_o3 regwptr[19]
++#define ureg_o4 regwptr[20]
++#define ureg_o5 regwptr[21]
++#define ureg_o6 regwptr[22]
++#define ureg_o7 regwptr[23]
++#define ureg_fp ureg_i6
++#define ureg_sp ureg_o6
++#define ureg_fprs fprs
++#define ureg_fsr fsr
++#define ureg_gsr gsr
++#define ureg_tnpc npc
++#define ureg_tpc pc
++#define ureg_y y
++
++#define TARGET_FPRS_FEF (1 << 2)
++#define TARGET_MC_VERSION 1L
++
+ #define TARGET_MINSIGSTKSZ (1024 * 4)
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
+-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
++#define TARGET_STACK_BIAS 2047 /* AKA. SPOFF */
++
++struct target_mcontext {
++ uint64_t mc_global[8];
++ uint64_t mc_out[8];
++ uint64_t mc_local[8];
++ uint64_t mc_in[8];
++ uint32_t mc_fp[64];
++} __aligned(64);
++
++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 {
++ target_ucontext_t sf_uc;
++ target_siginfo_t sf_si;
++};
++
++extern abi_ulong sparc_user_sigtramp;
++
++static inline int
++set_sigtramp_args(CPUSPARCState *regs, int sig, struct target_sigframe *frame,
++ abi_ulong frame_addr, struct target_sigaction *ka)
+ {
++
++ frame->sf_si.si_signo = sig;
++ frame->sf_si.si_code = TARGET_SA_SIGINFO;
++
++ /* Arguments to signal handler:
++ *
++ * i0 = signal number
++ * i1 = pointer to siginfo struct
++ * i2 = pointer to ucontext struct
++ * i3 = (not used in new style)
++ * i4 = signal handler address (called by sigtramp)
++ */
++ regs->ureg_i0 = sig;
++ regs->ureg_i1 = frame_addr +
++ offsetof(struct target_sigframe, sf_si);
++ regs->ureg_i2 = frame_addr +
++ offsetof(struct target_sigframe, sf_uc);
++ /* env->ureg_o3 used in the Old FreeBSD-style arguments. */
++ regs->ureg_i4 = ka->_sa_handler;
++ regs->ureg_tpc = sparc_user_sigtramp;
++ regs->ureg_tnpc = (regs->ureg_tpc + 4);
++ regs->ureg_sp = frame_addr - TARGET_STACK_BIAS;
++
++ return (0);
++}
++
++static inline abi_ulong
++get_sp_from_cpustate(CPUSPARCState *state)
++{
++
+ return state->regwptr[UREG_FP];
+ }
+
++/* compare to sparc64/sparc64/machdep.c get_mcontext() */
++static inline int
++get_mcontext(CPUSPARCState *regs, target_mcontext_t *mcp, int flags)
++{
++
++ /* Skip over the trap instruction, first. */
++ regs->pc = regs->npc;
++ regs->npc += 4;
++
++ mcp->mc_flags = TARGET_MC_VERSION; /* mc_global[0] */
++ mcp->mc_global[1] = tswapal(regs->gregs[1]);
++ mcp->mc_global[2] = tswapal(regs->gregs[2]);
++ mcp->mc_global[3] = tswapal(regs->gregs[3]);
++ mcp->mc_global[4] = tswapal(regs->gregs[4]);
++ mcp->mc_global[5] = tswapal(regs->gregs[5]);
++ mcp->mc_global[6] = tswapal(regs->gregs[6]);
++ /* skip %g7 since it is used as the userland TLS register */
++
++ if (flags & TARGET_MC_GET_CLEAR_RET) {
++ mcp->mc_out[0] = 0;
++ mcp->mc_out[1] = 0;
++ } else {
++ mcp->mc_out[0] = tswapal(regs->ureg_i0);
++ mcp->mc_out[1] = tswapal(regs->ureg_i1);
++ }
++ mcp->mc_out[2] = tswapal(regs->ureg_i2);
++ mcp->mc_out[3] = tswapal(regs->ureg_i3);
++ mcp->mc_out[4] = tswapal(regs->ureg_i4);
++ mcp->mc_out[5] = tswapal(regs->ureg_i5);
++ mcp->mc_out[6] = tswapal(regs->ureg_i6);
++ mcp->mc_out[7] = tswapal(regs->ureg_i7);
++
++ mcp->mc_fprs = tswapal(regs->fprs); /* mc_local[0] */
++ mcp->mc_fsr = tswapal(regs->fsr); /* mc_local[1] */
++ mcp->mc_gsr = tswapal(regs->gsr); /* mc_local[2] */
++
++ mcp->mc_tnpc = tswapal(regs->npc); /* mc_in[0] */
++ mcp->mc_tpc = tswapal(regs->pc); /* mc_in[1] */
++#if 0
++ mcp->mc_tstate = tswapal(regs->ureg_tstate); /* mc_in[2] */
++#else
++ abi_ulong cwp64 = cpu_get_cwp64(regs);
++ abi_ulong ccr = cpu_get_ccr(regs) << 32;
++ abi_ulong asi = (regs->asi & 0xff) << 24;
++ mcp->mc_tstate = tswapal(ccr | asi | cwp64);
++#endif
++
++ mcp->mc_y = tswapal(regs->y); /* mc_in[4] */
++
++ /* XXX
++ if ((regs->ureg_l0 & TARGET_FPRS_FEF) != 0) {
++ int i;
++
++ for(i = 0; i < 64; i++)
++ mcp->mc_fp[i] = tswapal(regs->fpr[i]);
++ }
++ */
++
++ return (0);
++}
++
++extern void helper_flushw(CPUSPARCState *env);
++
++/* compare to sparc64/sparc64/machdep.c set_mcontext() */
++static inline int
++set_mcontext(CPUSPARCState *regs, target_mcontext_t *mcp, int flags)
++{
++ /* XXX need to add version check here. */
++
++ /* Make sure the windows are spilled first. */
++ helper_flushw(regs);
++
++ regs->gregs[1] = tswapal(mcp->mc_global[1]);
++ regs->gregs[2] = tswapal(mcp->mc_global[2]);
++ regs->gregs[3] = tswapal(mcp->mc_global[3]);
++ regs->gregs[4] = tswapal(mcp->mc_global[4]);
++ regs->gregs[5] = tswapal(mcp->mc_global[5]);
++ regs->gregs[6] = tswapal(mcp->mc_global[6]);
++
++ regs->ureg_i0 = tswapal(mcp->mc_out[0]);
++ regs->ureg_i1 = tswapal(mcp->mc_out[1]);
++ regs->ureg_i2 = tswapal(mcp->mc_out[2]);
++ regs->ureg_i3 = tswapal(mcp->mc_out[3]);
++ regs->ureg_i4 = tswapal(mcp->mc_out[4]);
++ regs->ureg_i5 = tswapal(mcp->mc_out[5]);
++ regs->ureg_i6 = tswapal(mcp->mc_out[6]);
++ regs->ureg_i7 = tswapal(mcp->mc_out[7]);
++
++ regs->fprs = tswapal(mcp->mc_fprs); /* mc_local[0] */
++ regs->fsr = tswapal(mcp->mc_fsr); /* mc_local[1] */
++ regs->gsr = tswapal(mcp->mc_gsr); /* mc_local[2] */
++
++ regs->npc = tswapal(mcp->mc_tnpc); /* mc_in[0] */
++ regs->pc = tswapal(mcp->mc_tpc); /* mc_in[1] */
++
++#if 0
++ regs->ureg_tstate = tswapal(mcp->mc_tstate); /* mc_in[2] */
++#else
++ abi_ulong tstate = tswapal(mcp->mc_tstate); /* mc_in[2] */
++
++ regs->asi = (tstate >> 24) & 0xff;
++ cpu_put_ccr(regs, tstate >> 32);
++ cpu_put_cwp64(regs, tstate & 0x1f);
++
++#endif
++ regs->ureg_y = tswapal(mcp->mc_y); /* mc_in[4] */
++
++ /* XXX
++ if ((regs->ureg_fprs & TARGET_FPRS_FEF) != 0) {
++ int i;
++
++ regs->ureg_l0 = 0;
++ for(i = 0; i < 64; i++)
++ regs->fpr[i] = tswapal(mcp->mc_fp[i]);
++ }
++ */
++
++ return (0);
++}
++
+ #endif /* TARGET_SIGNAL_H */
+diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
+index 625c3cf..4deb0db 100644
+--- a/bsd-user/syscall.c
++++ b/bsd-user/syscall.c
+@@ -43,6 +43,12 @@
+ #ifdef __FreeBSD__
+ #include <sys/regression.h>
+ #include <sys/procdesc.h>
++#include <sys/ucontext.h>
++#include <sys/thr.h>
++#include <sys/rtprio.h>
++#include <sys/umtx.h>
++#include <pthread.h>
++#include <machine/atomic.h>
+ #endif
+ #include <sys/un.h>
+ #include <sys/ipc.h>
+@@ -251,7 +257,24 @@ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
+ #ifdef TARGET_MIPS
+ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
+ {
+- return -TARGET_EINVAL;
++ int ret = 0;
++ CPUMIPSState *mips_env = (CPUMIPSState *)env;
++
++ switch(op) {
++ case TARGET_MIPS_SET_TLS:
++ if (get_user(mips_env->tls_value, parms, abi_ulong))
++ ret = -TARGET_EFAULT;
++ break;
++ case TARGET_MIPS_GET_TLS:
++ if (put_user(mips_env->tls_value, parms, abi_ulong))
++ ret = -TARGET_EFAULT;
++ break;
++ default:
++ ret = -TARGET_EINVAL;
++ break;
++ }
++
++ return (ret);
+ }
+ #endif
+
+@@ -2119,6 +2142,383 @@ do_fork(CPUArchState *env, int num, int flags, int *fdp)
+ return (ret);
+ }
+
++#if defined(CONFIG_USE_NPTL)
++
++#define NEW_STACK_SIZE (0x40000)
++
++static pthread_mutex_t new_thread_lock = PTHREAD_MUTEX_INITIALIZER;
++typedef struct {
++ CPUArchState *env;
++ long tid;
++ pthread_mutex_t mutex;
++ pthread_cond_t cond;
++ pthread_t thread;
++ sigset_t sigmask;
++ struct target_thr_param param;
++} new_thread_info_t;
++
++static void *
++new_thread_start(void *arg)
++{
++ new_thread_info_t *info = arg;
++ CPUArchState *env;
++ TaskState *ts;
++ long tid;
++
++ env = info->env;
++ thread_env = env;
++ ts = (TaskState *)thread_env->opaque;
++ (void)thr_self(&tid);
++ info->tid = tid;
++ task_settid(ts);
++
++ /* copy out the TID info */
++ if (info->param.child_tid)
++ put_user(tid, info->param.child_tid, abi_long);
++ if (info->param.parent_tid)
++ put_user(tid, info->param.parent_tid, abi_long);
++
++#ifdef TARGET_MIPS64
++ CPUMIPSState *regs = env;
++ regs->active_tc.gpr[25] = regs->active_tc.PC = info->param.start_func;
++ regs->active_tc.gpr[ 4] = info->param.arg;
++ regs->active_tc.gpr[29] = info->param.stack_base;
++#endif
++ /* Eenable signals */
++ sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
++ /* Signal to the parent that we're ready. */
++ pthread_mutex_lock(&info->mutex);
++ pthread_cond_broadcast(&info->cond);
++ pthread_mutex_unlock(&info->mutex);
++ /* Wait until the parent has finished initializing the TLS state. */
++ pthread_mutex_lock(&new_thread_lock);
++ pthread_mutex_unlock(&new_thread_lock);
++
++ cpu_loop(env);
++ /* never exits */
++
++ return (NULL);
++}
++
++static void
++rtp_to_schedparam(const struct rtprio *rtp, int *policy, struct sched_param *param)
++{
++
++ switch(rtp->type) {
++ case RTP_PRIO_REALTIME:
++ *policy = SCHED_RR;
++ param->sched_priority = RTP_PRIO_MAX - rtp->prio;
++ break;
++
++ case RTP_PRIO_FIFO:
++ *policy = SCHED_FIFO;
++ param->sched_priority = RTP_PRIO_MAX - rtp->prio;
++ break;
++
++ default:
++ *policy = SCHED_OTHER;
++ param->sched_priority = 0;
++ break;
++ }
++}
++
++static int
++do_thr_create(CPUArchState *env, ucontext_t *ctx, long *id, int flags)
++{
++
++ return (unimplemented(TARGET_FREEBSD_NR_thr_create));
++}
++
++static int
++do_thr_new(CPUArchState *env, abi_ulong target_param_addr, int32_t param_size)
++{
++ new_thread_info_t info;
++ pthread_attr_t attr;
++ TaskState *ts;
++ CPUArchState *new_env;
++ struct target_thr_param *target_param;
++ abi_ulong target_rtp_addr;
++ struct target_rtprio *target_rtp;
++ struct rtprio *rtp_ptr, rtp;
++ TaskState *parent_ts = (TaskState *)env->opaque;
++ sigset_t sigmask;
++ struct sched_param sched_param;
++ int sched_policy;
++ int ret = 0;
++
++ memset(&info, 0, sizeof(info));
++
++ if (!lock_user_struct(VERIFY_READ, target_param, target_param_addr, 1))
++ return (-TARGET_EFAULT);
++ info.param.start_func = tswapal(target_param->start_func);
++ info.param.arg = tswapal(target_param->arg);
++ info.param.stack_base = tswapal(target_param->stack_base);
++ info.param.stack_size = tswapal(target_param->stack_size);
++ info.param.tls_base = tswapal(target_param->tls_base);
++ info.param.tls_size = tswapal(target_param->tls_size);
++ info.param.child_tid = tswapal(target_param->child_tid);
++ info.param.parent_tid = tswapal(target_param->parent_tid);
++ target_rtp_addr = info.param.rtp = tswapal(target_param->rtp);
++ unlock_user(target_param, target_param_addr, 0);
++
++ if (target_rtp_addr) {
++ if (!lock_user_struct(VERIFY_READ, target_rtp, target_rtp_addr,
++ 1))
++ return (-TARGET_EFAULT);
++ rtp.type = tswap16(target_rtp->type);
++ rtp.prio = tswap16(target_rtp->prio);
++ unlock_user(target_rtp, target_rtp_addr, 0);
++ rtp_ptr = &rtp;
++ } else {
++ rtp_ptr = NULL;
++ }
++
++ /* Create a new CPU instance. */
++ ts = g_malloc0(sizeof(TaskState));
++ init_task_state(ts);
++ new_env = cpu_copy(env);
++#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
++ cpu_reset(ENV_GET_CPU(new_env));
++#endif
++
++ /* init regs that differ from the parent thread. */
++ cpu_clone_regs(new_env, info.param.stack_base);
++ new_env->opaque = ts;
++ ts->bprm = parent_ts->bprm;
++ ts->info = parent_ts->info;
++
++#if defined(TARGET_MIPS)
++ env->tls_value = info.param.tls_base;
++ /* cpu_set_tls(new_env, info.param.tls_base); */
++#endif
++
++ /* Grab a mutex so that thread setup appears atomic. */
++ pthread_mutex_lock(&new_thread_lock);
++
++ pthread_mutex_init(&info.mutex, NULL);
++ pthread_mutex_lock(&info.mutex);
++ pthread_cond_init(&info.cond, NULL);
++ info.env = new_env;
++
++ /* XXX return value needs to be checked... */
++ pthread_attr_init(&attr);
++ pthread_attr_setstacksize(&attr, NEW_STACK_SIZE);
++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++ if (rtp_ptr) {
++ rtp_to_schedparam(&rtp, &sched_policy, &sched_param);
++ pthread_attr_setschedpolicy(&attr, sched_policy);
++ pthread_attr_setschedparam(&attr, &sched_param);
++ }
++
++ /*
++ * It is not safe to deliver signals until the child has finished
++ * initializing, so temporarily block all signals.
++ */
++ sigfillset(&sigmask);
++ sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
++
++ /* XXX return value needs to be checked... */
++ ret = pthread_create(&info.thread, &attr, new_thread_start, &info);
++ /* XXX Free new CPU state if thread creation fails. */
++
++ sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
++ pthread_attr_destroy(&attr);
++ if (0 == ret) {
++ /* Wait for the child to initialize. */
++ pthread_cond_wait(&info.cond, &info.mutex);
++ } else {
++ /* pthread_create failed. */
++ }
++
++ pthread_mutex_unlock(&info.mutex);
++ pthread_cond_destroy(&info.cond);
++ pthread_mutex_destroy(&info.mutex);
++ pthread_mutex_unlock(&new_thread_lock);
++
++ return (ret);
++}
++
++static int
++do_thr_self(long *id)
++{
++
++ return (get_errno(thr_self(id)));
++}
++
++static void
++do_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr)
++{
++
++ if (first_cpu->next_cpu) {
++ TaskState *ts;
++ CPUArchState **lastp, *p;
++
++ /*
++ * *XXX This probably breaks if a signal arrives.
++ * We should disable signals.
++ */
++ cpu_list_lock();
++ lastp = &first_cpu;
++ p = first_cpu;
++ while (p && p != (CPUArchState *)cpu_env) {
++ lastp = &p->next_cpu;
++ p = p->next_cpu;
++ }
++ /*
++ * if we didn't find the CPU for this thread then something
++ * is horribly wrong.
++ */
++ if (!p)
++ abort();
++ /* Remove the CPU from the list. */
++ *lastp = p->next_cpu;
++ cpu_list_unlock();
++ ts = ((CPUArchState *)cpu_env)->opaque;
++
++ if (tid_addr) {
++ /* Signal target userland that it can free the stack. */
++ if (! put_user_u32(1, tid_addr))
++ _umtx_op(g2h(tid_addr), UMTX_OP_WAKE, INT_MAX,
++ NULL, NULL);
++ }
++
++ thread_env = NULL;
++ object_delete(OBJECT(ENV_GET_CPU(cpu_env)));
++ g_free(ts);
++ pthread_exit(NULL);
++ }
++}
++
++static int
++do_thr_kill(long id, int sig)
++{
++
++ return (get_errno(thr_kill(id, sig)));
++}
++
++static int
++do_thr_kill2(pid_t pid, long id, int sig)
++{
++
++ return (get_errno(thr_kill2(pid, id, sig)));
++}
++
++static int
++do_thr_suspend(const struct timespec *timeout)
++{
++
++ return (get_errno(thr_suspend(timeout)));
++}
++
++static int
++do_thr_wake(long tid)
++{
++
++ return (get_errno(thr_wake(tid)));
++}
++
++static int
++do_thr_set_name(long tid, char *name)
++{
++
++ return (get_errno(thr_set_name(tid, name)));
++}
++
++
++#else /* ! CONFIG_USE_NPTL */
++
++static int
++do_thr_create(CPUArchState *env, ucontext_t *ctx, long *id, int flags)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_create));
++}
++
++static int
++do_thr_new(CPUArchState *env, abi_ulong target_param_addr, int32_t param_size)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_new));
++}
++
++static int
++do_thr_self(long *tid)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_self));
++}
++
++static void
++do_thr_exit(CPUArchState *cpu_env, abi_ulong state_addr)
++{
++}
++
++static int
++do_thr_kill(long tid, int sig)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_kill2));
++}
++
++static int
++do_thr_kill2(pid_t pid, long tid, int sig)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_kill2));
++}
++
++static int
++do_thr_suspend(const struct timespec *timeout)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_suspend));
++}
++
++static int
++do_thr_wake(long tid)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_wake));
++}
++
++static int
++do_thr_set_name(long tid, char *name)
++{
++ return (unimplemented(TARGET_FREEBSD_NR_thr_set_name));
++}
++
++#endif /* CONFIG_USE_NPTL */
++
++static int
++do_umtx_lock(abi_ulong umtx_addr, uint32_t id)
++{
++ int ret = 0;
++
++ for (;;) {
++ ret = get_errno(_umtx_op(g2h(umtx_addr +
++ offsetof(struct target_umtx, u_owner)),
++ UMTX_OP_MUTEX_WAIT, UMTX_UNOWNED, 0, 0));
++ if (ret)
++ return (ret);
++ if (atomic_cmpset_acq_32(g2h(umtx_addr +
++ offsetof(struct target_umtx, u_owner)),
++ UMTX_UNOWNED, id))
++ return (0);
++ }
++}
++
++static int
++do_umtx_unlock(abi_ulong umtx_addr, uint32 id)
++{
++ uint32_t owner;
++
++ do {
++ if (get_user_u32(owner, umtx_addr +
++ offsetof(struct target_umtx, u_owner)))
++ return (-TARGET_EFAULT);
++ if (owner != id)
++ return (-TARGET_EPERM);
++ } while (!atomic_cmpset_rel_32(g2h(umtx_addr +
++ offsetof(struct target_umtx, u_owner)), owner,
++ UMUTEX_UNOWNED));
++
++ return (0);
++}
++
++
+ /* do_syscall() should always have a single exit point at the end so
+ that actions, such as logging of syscall results, can be performed.
+ All errnos that do_syscall() returns must be -TARGET_<errcode>. */
+@@ -4091,6 +4491,23 @@ do_stat:
+ break;
+ #endif
+
++#ifdef TARGET_FREEBSD_NR_getdomainname
++ case TARGET_FREEBSD_NR_getdomainname:
++ ret = unimplemented(num);
++ break;
++#endif
++#ifdef TARGET_FREEBSD_NR_setdomainname
++ case TARGET_FREEBSD_NR_setdomainname:
++ ret = unimplemented(num);
++ break;
++#endif
++#ifdef TARGET_FREEBSD_NR_uname
++ case TARGET_FREEBSD_NR_uname:
++ ret = unimplemented(num);
++ break;
++#endif
++
++
+ #if 0 /* XXX not supported in libc yet, it seems (10.0 addition). */
+ case TARGET_FREEBSD_NR_posix_fadvise:
+ {
+@@ -4136,6 +4553,211 @@ do_stat:
+ break;
+ #endif
+
++ case TARGET_FREEBSD_NR_thr_new:
++ ret = do_thr_new(cpu_env, arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_thr_create:
++ {
++ ucontext_t ucxt;
++ long tid;
++
++ ret = do_thr_create(cpu_env, &ucxt, &tid, arg3);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_thr_set_name:
++ if (!(p = lock_user_string(arg2)))
++ goto efault;
++ ret = do_thr_set_name(arg1, p);
++ unlock_user(p, arg2, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_thr_self:
++ {
++ long tid;
++
++ if ((ret = do_thr_self(&tid)) == 0) {
++ if (put_user((abi_long)tid, arg1, abi_long))
++ goto efault;
++ }
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_thr_suspend:
++ {
++ struct timespec ts;
++
++ if (target_to_host_timespec(&ts, arg1))
++ goto efault;
++
++ ret = do_thr_suspend(&ts);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_thr_wake:
++ ret = do_thr_wake(arg1);
++ break;
++
++ case TARGET_FREEBSD_NR_thr_kill:
++ ret = do_thr_kill(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_thr_kill2:
++ ret = do_thr_kill2(arg1, arg2, arg3);
++ break;
++
++ case TARGET_FREEBSD_NR_thr_exit:
++ ret = 0; /* suspress compile warning */
++ do_thr_exit(cpu_env, arg1);
++ /* Shouldn't be reached. */
++ break;
++
++ case TARGET_FREEBSD_NR_rtprio_thread:
++ ret = 0;
++ break;
++
++ case TARGET_FREEBSD_NR_getcontext:
++ {
++ target_ucontext_t *ucp;
++ sigset_t sigmask;
++
++ if (0 == arg1) {
++ ret = -TARGET_EINVAL;
++ } else {
++ ret = get_errno(sigprocmask(0, NULL, &sigmask));
++ if (!is_error(ret)) {
++ if (!(ucp = lock_user(VERIFY_WRITE, arg1,
++ sizeof(target_ucontext_t), 0)))
++ goto efault;
++ ret = get_mcontext(cpu_env, &ucp->uc_mcontext,
++ TARGET_MC_GET_CLEAR_RET);
++ host_to_target_sigset(&ucp->uc_sigmask,
++ &sigmask);
++ memset(ucp->__spare__, 0,
++ sizeof(ucp->__spare__));
++ unlock_user(ucp, arg1,
++ sizeof(target_ucontext_t));
++ }
++ }
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_setcontext:
++ {
++ target_ucontext_t *ucp;
++ sigset_t sigmask;
++
++ if (0 == arg1) {
++ ret = -TARGET_EINVAL;
++ } else {
++ if (!(ucp = lock_user(VERIFY_READ, arg1,
++ sizeof(target_ucontext_t), 1)))
++ goto efault;
++ ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0);
++ target_to_host_sigset(&sigmask, &ucp->uc_sigmask);
++ unlock_user(ucp, arg1, sizeof(target_ucontext_t));
++ if (0 == ret)
++ (void)sigprocmask(SIG_SETMASK, &sigmask, NULL);
++ }
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_swapcontext:
++ /*
++ * XXX Does anything besides old implementations of
++ * setjmp()/longjmp() uses these?
++ */
++ ret = unimplemented(num);
++ break;
++
++ case TARGET_FREEBSD_NR__umtx_lock:
++ {
++ long tid;
++
++ thr_self(&tid);
++ ret = do_umtx_lock(arg1, tswap32(tid));
++ }
++ break;
++
++ case TARGET_FREEBSD_NR__umtx_unlock:
++ {
++ long tid;
++
++ thr_self(&tid);
++ ret = do_umtx_unlock(arg1, tswap32(tid));
++ }
++ break;
++
++ case TARGET_FREEBSD_NR__umtx_op:
++ {
++ struct timespec ts;
++ void *object = NULL;
++ int operation;
++ void *addr = NULL;
++ void *addr2 = NULL;
++
++
++ /* int _umtx_op(void *obj, int op, u_long val,
++ * void *uaddr, void *uaddr2); */
++
++ abi_ulong obj = arg1;
++ int op = (int)arg2;
++ u_long val = arg3;
++ /* abi_ulong uaddr = arg4; */
++ abi_ulong uaddr2 = arg5;
++
++ switch(op) {
++ case TARGET_UMTX_OP_LOCK:
++ ret = do_umtx_lock(obj, tswap32((uint32_t)val));
++ break;
++
++ case TARGET_UMTX_OP_UNLOCK:
++ ret = do_umtx_unlock(obj, tswap32((uint32_t)val));
++ break;
++
++ case TARGET_UMTX_OP_WAIT:
++ if (uaddr2) {
++ if (target_to_host_timespec(&ts, uaddr2))
++ goto efault;
++ addr2 = (void *)&ts;
++ }
++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT,
++ tswap32(val), addr, addr2));
++ break;
++
++ case TARGET_UMTX_OP_WAKE:
++ operation = UMTX_OP_WAKE;
++ object = g2h(obj);
++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_WAKE,
++ val, 0, 0));
++ break;
++
++ case TARGET_UMTX_OP_MUTEX_TRYLOCK:
++ case TARGET_UMTX_OP_MUTEX_LOCK:
++ case TARGET_UMTX_OP_MUTEX_UNLOCK:
++ case TARGET_UMTX_OP_SET_CEILING:
++ case TARGET_UMTX_OP_CV_WAIT:
++ case TARGET_UMTX_OP_CV_SIGNAL:
++ case TARGET_UMTX_OP_CV_BROADCAST:
++ case TARGET_UMTX_OP_WAIT_UINT:
++ case TARGET_UMTX_OP_RW_RDLOCK:
++ case TARGET_UMTX_OP_RW_WRLOCK:
++ case TARGET_UMTX_OP_RW_UNLOCK:
++ case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
++ case TARGET_UMTX_OP_WAKE_PRIVATE:
++ case TARGET_UMTX_OP_MUTEX_WAIT:
++ case TARGET_UMTX_OP_MUTEX_WAKE:
++ case TARGET_UMTX_OP_SEM_WAIT:
++ case TARGET_UMTX_OP_SEM_WAKE:
++ case TARGET_UMTX_OP_NWAKE_PRIVATE:
++ default:
++ ret = -TARGET_EINVAL;
++ break;
++ }
++ }
++ break;
++
+ case TARGET_FREEBSD_NR_yield:
+ case TARGET_FREEBSD_NR_sched_setparam:
+ case TARGET_FREEBSD_NR_sched_getparam:
+@@ -4146,36 +4768,18 @@ do_stat:
+ case TARGET_FREEBSD_NR_sched_get_priority_min:
+ case TARGET_FREEBSD_NR_sched_rr_get_interval:
+
+-
+ case TARGET_FREEBSD_NR_reboot:
+ case TARGET_FREEBSD_NR_shutdown:
+
+ case TARGET_FREEBSD_NR_swapon:
+ case TARGET_FREEBSD_NR_swapoff:
+
+- case TARGET_FREEBSD_NR_thr_create:
+- case TARGET_FREEBSD_NR_thr_exit:
+- case TARGET_FREEBSD_NR_thr_self:
+- case TARGET_FREEBSD_NR_thr_suspend:
+- case TARGET_FREEBSD_NR_thr_wake:
+- case TARGET_FREEBSD_NR_thr_new:
+- case TARGET_FREEBSD_NR_thr_set_name:
+- case TARGET_FREEBSD_NR_thr_kill2:
+-
+- case TARGET_FREEBSD_NR_getcontext:
+- case TARGET_FREEBSD_NR_setcontext:
+- case TARGET_FREEBSD_NR_swapcontext:
+-
+- case TARGET_FREEBSD_NR_rtprio_thread:
+ case TARGET_FREEBSD_NR_cpuset:
+ case TARGET_FREEBSD_NR_cpuset_getid:
+ case TARGET_FREEBSD_NR_cpuset_setid:
+ case TARGET_FREEBSD_NR_cpuset_getaffinity:
+ case TARGET_FREEBSD_NR_cpuset_setaffinity:
+
+- case TARGET_FREEBSD_NR__umtx_lock:
+- case TARGET_FREEBSD_NR__umtx_unlock:
+-
+ case TARGET_FREEBSD_NR_rctl_get_racct:
+ case TARGET_FREEBSD_NR_rctl_get_rules:
+ case TARGET_FREEBSD_NR_rctl_add_rule:
+@@ -4185,16 +4789,6 @@ do_stat:
+ case TARGET_FREEBSD_NR_ntp_adjtime:
+ case TARGET_FREEBSD_NR_ntp_gettime:
+
+-#ifdef TARGET_FREEBSD_NR_getdomainname
+- case TARGET_FREEBSD_NR_getdomainname:
+-#endif
+-#ifdef TARGET_FREEBSD_NR_setdomainname
+- case TARGET_FREEBSD_NR_setdomainname:
+-#endif
+-#ifdef TARGET_FREEBSD_NR_uname
+- case TARGET_FREEBSD_NR_uname:
+-#endif
+-
+ case TARGET_FREEBSD_NR_sctp_peeloff:
+ case TARGET_FREEBSD_NR_sctp_generic_sendmsg:
+ case TARGET_FREEBSD_NR_sctp_generic_recvmsg:
+diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
+index ea1d25d..2879d83 100644
+--- a/bsd-user/syscall_defs.h
++++ b/bsd-user/syscall_defs.h
+@@ -416,6 +416,11 @@ struct target_shmid_ds {
+ abi_ulong shm_ctime; /* time of last change by shmctl() */
+ };
+
++#define TARGET_UCONTEXT_MAGIC 0xACEDBADE
++#define TARGET_MC_GET_CLEAR_RET 0x0001
++#define TARGET_MC_ADD_MAGIC 0x0002
++#define TARGET_MC_SET_ONSTACK 0x0004
++
+ /* this struct defines a stack used during syscall handling */
+ typedef struct target_sigaltstack {
+ abi_long ss_sp;
+@@ -477,95 +482,6 @@ typedef struct target_siginfo {
+ } _reason;
+ } target_siginfo_t;
+
+-#if defined(TARGET_MIPS)
+-
+-struct target_sigcontext {
+- target_sigset_t sc_mask; /* signal mask to retstore */
+- int32_t sc_onstack; /* sigstack state to restore */
+- abi_long sc_pc; /* pc at time of signal */
+- abi_long sc_reg[32]; /* processor regs 0 to 31 */
+- abi_long mullo, mulhi; /* mullo and mulhi registers */
+- int32_t sc_fpused; /* fp has been used */
+- abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */
+- abi_long sc_fpc_eir; /* fp exception instr reg */
+- /* int32_t reserved[8]; */
+-};
+-
+-typedef struct target_mcontext {
+- int32_t mc_onstack; /* sigstack state to restore */
+- abi_long mc_pc; /* pc at time of signal */
+- abi_long mc_regs[32]; /* process regs 0 to 31 */
+- abi_long sr; /* status register */
+- abi_long mullo, mulhi;
+- int32_t mc_fpused; /* fp has been used */
+- abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */
+- abi_long mc_fpc_eir; /* fp exception instr reg */
+- abi_ulong mc_tls; /* pointer to TLS area */
+-} target_mcontext_t;
+-
+-typedef struct target_ucontext {
+- target_sigset_t uc_sigmask;
+- target_mcontext_t uc_mcontext;
+- target_ulong uc_link;
+- target_stack_t uc_stack;
+- int32_t uc_flags;
+- int32_t __space__[8];
+-} 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];
+-};
+-
+-#elif defined(TARGET_SPARC64)
+-
+-struct target_mcontext {
+- uint64_t mc_global[8];
+- uint64_t mc_out[8];
+- uint64_t mc_local[8];
+- uint64_t mc_in[8];
+- uint32_t mc_fp[64];
+-} __aligned(64);
+-
+-typedef struct target_mcontext target_mcontext_t;
+-
+-typedef struct target_ucontext {
+- target_sigset_t uc_sigmask;
+- target_mcontext_t uc_mcontext;
+- target_ulong uc_link;
+- target_stack_t uc_stack;
+- int32_t uc_flags;
+- int32_t __space__[8];
+-} target_ucontext_t;
+-
+-struct target_sigframe {
+- target_ucontext_t sf_uc;
+- target_siginfo_t sf_si;
+-};
+-
+-#else
+-
+-typedef target_ulong target_mcontext_t; /* dummy */
+-
+-#endif
+-
+-/* XXX where did this come from?
+-typedef struct target_ucontext {
+- target_ulong uc_flags;
+- target_ulong uc_link;
+- target_stack_t uc_stack;
+- target_mcontext_t uc_mcontext;
+- target_ulong uc_filer[80];
+- target_sigset_t uc_sigmask;
+-} target_ucontext_t;
+-*/
+-
+-
+ #ifdef BSWAP_NEEDED
+ static inline void
+ tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
+@@ -603,3 +519,101 @@ void host_to_target_old_sigset(abi_ulong *old_sigset, const sigset_t *sigset);
+ void target_to_host_old_sigset(sigset_t *sigset, const abi_ulong *old_sigset);
+ int do_sigaction(int sig, const struct target_sigaction *act,
+ struct target_sigaction *oact);
++
++
++/*
++ * FreeBSD thread support.
++ */
++
++#define TARGET_THR_SUSPENDED 0x0001
++#define TARGET_THR_SYSTEM_SCOPE 0x0002
++
++/* sysarch() ops */
++#define TARGET_MIPS_SET_TLS 1
++#define TARGET_MIPS_GET_TLS 2
++
++struct target_thr_param {
++ abi_ulong start_func; /* thread entry function. */
++ abi_ulong arg; /* argument for entry function. */
++ abi_ulong stack_base; /* stack base address. */
++ abi_ulong stack_size; /* stack size. */
++ abi_ulong tls_base; /* tls base address. */
++ abi_ulong tls_size; /* tls size. */
++ abi_ulong child_tid; /* address to store new TID. */
++ abi_ulong parent_tid; /* parent access the new TID here. */
++ abi_ulong rtp; /* Real-time scheduling priority. */
++ abi_ulong spare[3]; /* spares. */
++};
++
++struct target_rtprio {
++ uint16_t type;
++ uint16_t prio;
++};
++
++/*
++ * sys/_umtx.h
++ */
++
++struct target_umtx {
++ uint32_t u_owner; /* Owner of the mutex. */
++};
++
++struct target_umutex {
++ uint32_t m_owner; /* Owner of the mutex */
++ uint32_t m_flags; /* Flags of the mutex */
++ uint32_t m_ceiling[2]; /* Priority protect ceiling */
++ uint32_t m_spare[4];
++};
++
++struct target_ucond {
++ uint32_t c_has_waiters; /* Has waiters in kernel */
++ uint32_t c_flags; /* Flags of the condition variable */
++ uint32_t c_clockid; /* Clock id */
++ uint32_t c_spare[1];
++};
++
++struct target_urwlock {
++ int32_t rw_state;
++ uint32_t rw_flags;
++ uint32_t rw_blocked_readers;
++ uint32_t rw_blocked_writers;
++ uint32_t rw_spare[4];
++};
++
++struct target__usem {
++ uint32_t _has_waiters;
++ uint32_t _count;
++ uint32_t _flags;
++};
++
++/*
++ * sys/utmx.h
++ */
++
++/* op code for _umtx_op */
++#define TARGET_UMTX_OP_LOCK 0
++#define TARGET_UMTX_OP_UNLOCK 1
++#define TARGET_UMTX_OP_WAIT 2
++#define TARGET_UMTX_OP_WAKE 3
++#define TARGET_UMTX_OP_MUTEX_TRYLOCK 4
++#define TARGET_UMTX_OP_MUTEX_LOCK 5
++#define TARGET_UMTX_OP_MUTEX_UNLOCK 6
++#define TARGET_UMTX_OP_SET_CEILING 7
++#define TARGET_UMTX_OP_CV_WAIT 8
++#define TARGET_UMTX_OP_CV_SIGNAL 9
++#define TARGET_UMTX_OP_CV_BROADCAST 10
++#define TARGET_UMTX_OP_WAIT_UINT 11
++#define TARGET_UMTX_OP_RW_RDLOCK 12
++#define TARGET_UMTX_OP_RW_WRLOCK 13
++#define TARGET_UMTX_OP_RW_UNLOCK 14
++#define TARGET_UMTX_OP_WAIT_UINT_PRIVATE 15
++#define TARGET_UMTX_OP_WAKE_PRIVATE 16
++#define TARGET_UMTX_OP_MUTEX_WAIT 17
++#define TARGET_UMTX_OP_MUTEX_WAKE 18
++#define TARGET_UMTX_OP_SEM_WAIT 19
++#define TARGET_UMTX_OP_SEM_WAKE 20
++#define TARGET_UMTX_OP_NWAKE_PRIVATE 21
++#define TARGET_UMTX_OP_MAX 22
++
++/* flags for UMTX_OP_CV_WAIT */
++#define TARGET_CHECK_UNPARKING 0x01
+diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h
+index ea89f5a..a14e0b9 100644
+--- a/bsd-user/x86_64/target_signal.h
++++ b/bsd-user/x86_64/target_signal.h
+@@ -15,4 +15,29 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+ #define TARGET_MINSIGSTKSZ (512 * 4)
+ #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
++typedef target_ulong target_mcontext_t; /* dummy */
++
++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;
++
++static inline int
++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "x86_64 doesn't have support for get_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
++static inline int
++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags)
++{
++ fprintf(stderr, "x86_64 doesn't have support for set_mcontext()\n");
++ return (-TARGET_ENOSYS);
++}
++
+ #endif /* TARGET_SIGNAL_H */
+diff --git a/configure b/configure
+index 34eca43..be75584 100755
+--- a/configure
++++ b/configure
+@@ -1386,6 +1386,11 @@ fi
+
+ if test "$nptl" != "no" ; then
+ cat > $TMPC <<EOF
++#ifdef __FreeBSD__
++int main(void) {
++ return (0);
++}
++#else
+ #include <sched.h>
+ #include <linux/futex.h>
+ int main(void) {
+@@ -1394,6 +1399,7 @@ int main(void) {
+ #endif
+ return 0;
+ }
++#endif
+ EOF
+
+ if compile_object ; then
+@@ -3751,5 +3757,6 @@ case "$target_arch2" in
+ TARGET_ARCH=mips64
+ TARGET_BASE_ARCH=mips
+ echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
++ target_nptl="yes"
+ target_long_alignment=8
+ ;;