summaryrefslogtreecommitdiff
path: root/emulators/qemu-devel/files/patch-z2e-bsd-user-sson-002e
diff options
context:
space:
mode:
Diffstat (limited to 'emulators/qemu-devel/files/patch-z2e-bsd-user-sson-002e')
-rw-r--r--emulators/qemu-devel/files/patch-z2e-bsd-user-sson-002e3316
1 files changed, 3316 insertions, 0 deletions
diff --git a/emulators/qemu-devel/files/patch-z2e-bsd-user-sson-002e b/emulators/qemu-devel/files/patch-z2e-bsd-user-sson-002e
new file mode 100644
index 000000000000..969b6b825640
--- /dev/null
+++ b/emulators/qemu-devel/files/patch-z2e-bsd-user-sson-002e
@@ -0,0 +1,3316 @@
+diff --git a/Makefile.target b/Makefile.target
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -95,7 +95,7 @@ ifdef CONFIG_BSD_USER
+ QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
+
+ obj-y += bsd-user/
+-obj-y += gdbstub.o user-exec.o
++obj-y += gdbstub.o thunk.o user-exec.o
+
+ endif #CONFIG_BSD_USER
+
+diff --git a/bsd-user/freebsd/ioccom.h b/bsd-user/freebsd/ioccom.h
+new file mode 100644
+index 0000000..830e377
+--- /dev/null
++++ b/bsd-user/freebsd/ioccom.h
+@@ -0,0 +1,34 @@
++#ifndef _FREEBSD_IOCCOM_H_
++#define _FREEBSD_IOCCOM_H_
++/*
++ * Ioctl's have the command encoded in the lower word, and the size of
++ * any in or out parameters in the upper word. The high 3 bits of the
++ * upper word are used to encode the in/out status of the parameter.
++ */
++/* number of bits for ioctl size */
++#define TARGET_IOCPARM_SHIFT 13
++
++/* parameter length mask */
++#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1)
++
++#define TARGET_IOCPARM_LEN(x) (((x) >> 16) & TARGET_IOCPARM_MASK)
++#define TARGET_IOCBASECMD(x) ((x) & ~(TARGET_IOCPARM_MASK << 16))
++#define TARGET_IOCGROUP(x) (((x) >> 8) & 0xff)
++
++#define TARGET_IOCPARM_MAX (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */
++#define TARGET_IOC_VOID 0x20000000 /* no parameters */
++#define TARGET_IOC_OUT 0x40000000 /* copy out parameters */
++#define TARGET_IOC_IN 0x80000000 /* copy in parameters */
++#define TARGET_IOC_INOUT (TARGET_IOC_IN|TARGET_IOC_OUT)
++#define TARGET_IOC_DIRMASK (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN)
++
++#define TARGET_IOC(inout,group,num,len) ((abi_ulong) \
++ ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \
++ | (num)))
++#define TARGET_IO(g,n) TARGET_IOC(IOC_VOID, (g), (n), 0)
++#define TARGET_IOWINT(g,n) TARGET_IOC(IOC_VOID, (g), (n), sizeof(int))
++#define TARGET_IOR(g,n,t) TARGET_IOC(IOC_OUT, (g), (n), sizeof(t))
++#define TARGET_IOW(g,n,t) TARGET_IOC(IOC_IN, (g), (n), sizeof(t))
++/* this should be _IORW, but stdio got there first */
++#define TARGET_IOWR(g,n,t) TARGET_IOC(IOC_INOUT, (g), (n), sizeof(t))
++#endif
+diff --git a/bsd-user/freebsd/ioctl.h b/bsd-user/freebsd/ioctl.h
+new file mode 100644
+index 0000000..67c5583
+--- /dev/null
++++ b/bsd-user/freebsd/ioctl.h
+@@ -0,0 +1,35 @@
++#ifndef _FREEBSD_IOCTL_H_
++#define _FREEBSD_IOCTL_H_
++
++/* sys/ttycom.h tty(4) */
++IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
++IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
++IOCTL(TIOCSBRK, IOC_, TYPE_NULL)
++IOCTL(TIOCCBRK, IOC_, TYPE_NULL)
++IOCTL(TIOCSDTR, IOC_, TYPE_NULL)
++IOCTL(TIOCCDTR, IOC_, TYPE_NULL)
++IOCTL(TIOCGPGRP, IOC_W, MK_PTR(TYPE_INT))
++IOCTL(TIOCSPGRP, IOC_R, MK_PTR(TYPE_INT))
++IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
++IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
++IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
++IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
++IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
++IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR))
++IOCTL(TIOCNOTTY, IOC_, TYPE_NULL)
++IOCTL(TIOCSTOP, IOC_, TYPE_NULL)
++IOCTL(TIOCSTART, IOC_, TYPE_NULL)
++IOCTL(TIOCSCTTY, IOC_, TYPE_NULL)
++IOCTL(TIOCDRAIN, IOC_, TYPE_NULL)
++IOCTL(TIOCEXCL, IOC_, TYPE_NULL)
++IOCTL(TIOCNXCL, IOC_, TYPE_NULL)
++IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT))
++IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
++IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
++IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT))
++IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
++IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
++IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
++IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
++
++#endif
+diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list
+index b09f766..bcdd931 100644
+--- a/bsd-user/freebsd/strace.list
++++ b/bsd-user/freebsd/strace.list
+@@ -2,6 +2,7 @@
+ { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL },
+ { TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL },
++{ TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL },
+ { TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL },
+ { TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL },
+ { TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL },
+diff --git a/bsd-user/freebsd/syscall_types.h b/bsd-user/freebsd/syscall_types.h
+new file mode 100644
+index 0000000..6e43400
+--- /dev/null
++++ b/bsd-user/freebsd/syscall_types.h
+@@ -0,0 +1,8 @@
++#ifndef _FREEBSD_SYSCALL_TYPES_H_
++#define _FREEBSD_SYSCALL_TYPES_H_
++
++STRUCT_SPECIAL(termios)
++
++STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
++
++#endif
+diff --git a/bsd-user/freebsd/ttycom.h b/bsd-user/freebsd/ttycom.h
+new file mode 100644
+index 0000000..699c282
+--- /dev/null
++++ b/bsd-user/freebsd/ttycom.h
+@@ -0,0 +1,238 @@
++#ifndef _FREEBSD_TTYCOM_H_
++#define _FREEBSD_TTYCOM_H_
++
++#include "ioccom.h"
++
++/* From sys/ttycom.h and sys/_termios.h */
++
++#define TARGET_VEOF 0 /* ICANON */
++#define TARGET_VEOL 1 /* ICANON */
++#define TARGET_VEOL2 2 /* ICANON together with IEXTEN */
++#define TARGET_VERASE 3 /* ICANON */
++#define TARGET_VWERASE 4 /* ICANON together with IEXTEN */
++#define TARGET_VKILL 5 /* ICANON */
++#define TARGET_VREPRINT 6 /* ICANON together with IEXTEN */
++#define TARGET_VERASE2 7 /* ICANON */
++#define TARGET_VINTR 8 /* ISIG */
++#define TARGET_VQUIT 9 /* ISIG */
++#define TARGET_VSUSP 10 /* ISIG */
++#define TARGET_VDSUSP 11 /* ISIG together with IEXTEN */
++#define TARGET_VSTART 12 /* IXON, IXOFF */
++#define TARGET_VSTOP 13 /* IXON, IXOFF */
++#define TARGET_VLNEXT 14 /* IEXTEN */
++#define TARGET_VDISCARD 15 /* IEXTEN */
++#define TARGET_VMIN 16 /* !ICANON */
++#define TARGET_VTIME 17 /* !ICANON */
++#define TARGET_VSTATUS 18 /* ICANON together with IEXTEN */
++/* 19 spare 2 */
++#define TARGET_NCCS 20
++
++/*
++ * Input flags - software input processing
++ */
++#define TARGET_IGNBRK 0x00000001 /* ignore BREAK condition */
++#define TARGET_BRKINT 0x00000002 /* map BREAK to SIGINTR */
++#define TARGET_IGNPAR 0x00000004 /* ignore (discard) parity errors */
++#define TARGET_PARMRK 0x00000008 /* mark parity and framing errors */
++#define TARGET_INPCK 0x00000010 /* enable checking of parity errors */
++#define TARGET_ISTRIP 0x00000020 /* strip 8th bit off chars */
++#define TARGET_INLCR 0x00000040 /* map NL into CR */
++#define TARGET_IGNCR 0x00000080 /* ignore CR */
++#define TARGET_ICRNL 0x00000100 /* map CR to NL (ala CRMOD) */
++#define TARGET_IXON 0x00000200 /* enable output flow control */
++#define TARGET_IXOFF 0x00000400 /* enable input flow control */
++#define TARGET_IXANY 0x00000800 /* any char will restart after stop */
++#define TARGET_IMAXBEL 0x00002000 /* ring bell on input queue full */
++
++/*
++ * Output flags - software output processing
++ */
++#define TARGET_OPOST 0x00000001 /* enable following output processing */
++#define TARGET_ONLCR 0x00000002 /* map NL to CR-NL (ala CRMOD) */
++#define TARGET_TABDLY 0x00000004 /* tab delay mask */
++#define TARGET_TAB0 0x00000000 /* no tab delay and expansion */
++#define TARGET_TAB3 0x00000004 /* expand tabs to spaces */
++#define TARGET_ONOEOT 0x00000008 /* discard EOT's (^D) on output) */
++#define TARGET_OCRNL 0x00000010 /* map CR to NL on output */
++#define TARGET_ONOCR 0x00000020 /* no CR output at column 0 */
++#define TARGET_ONLRET 0x00000040 /* NL performs CR function */
++
++/*
++ * Control flags - hardware control of terminal
++ */
++#define TARGET_CIGNORE 0x00000001 /* ignore control flags */
++#define TARGET_CSIZE 0x00000300 /* character size mask */
++#define TARGET_CS5 0x00000000 /* 5 bits (pseudo) */
++#define TARGET_CS6 0x00000100 /* 6 bits */
++#define TARGET_CS7 0x00000200 /* 7 bits */
++#define TARGET_CS8 0x00000300 /* 8 bits */
++#define TARGET_CSTOPB 0x00000400 /* send 2 stop bits */
++#define TARGET_CREAD 0x00000800 /* enable receiver */
++#define TARGET_PARENB 0x00001000 /* parity enable */
++#define TARGET_PARODD 0x00002000 /* odd parity, else even */
++#define TARGET_HUPCL 0x00004000 /* hang up on last close */
++#define TARGET_CLOCAL 0x00008000 /* ignore modem status lines */
++#define TARGET_CCTS_OFLOW 0x00010000 /* CTS flow control of output */
++#define TARGET_CRTSCTS (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW)
++#define TARGET_CRTS_IFLOW 0x00020000 /* RTS flow control of input */
++#define TARGET_CDTR_IFLOW 0x00040000 /* DTR flow control of input */
++#define TARGET_CDSR_OFLOW 0x00080000 /* DSR flow control of output */
++#define TARGET_CCAR_OFLOW 0x00100000 /* DCD flow control of output */
++
++/*
++ * "Local" flags - dumping ground for other state
++ */
++#define TARGET_ECHOKE 0x00000001 /* visual erase for line kill */
++#define TARGET_ECHOE 0x00000002 /* visually erase chars */
++#define TARGET_ECHOK 0x00000004 /* echo NL after line kill */
++#define TARGET_ECHO 0x00000008 /* enable echoing */
++#define TARGET_ECHONL 0x00000010 /* echo NL even if ECHO is off */
++#define TARGET_ECHOPRT 0x00000020 /* visual erase mode for hardcopy */
++#define TARGET_ECHOCTL 0x00000040 /* echo control chars as ^(Char) */
++#define TARGET_ISIG 0x00000080 /* enable signals INTR, QUIT, [D]SUSP */
++#define TARGET_ICANON 0x00000100 /* canonicalize input lines */
++#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */
++#define TARGET_IEXTEN 0x00000400 /* enable DISCARD and LNEXT */
++#define TARGET_EXTPROC 0x00000800 /* external processing */
++#define TARGET_TOSTOP 0x00400000 /* stop background jobs from output */
++#define TARGET_FLUSHO 0x00800000 /* output being flushed (state) */
++#define TARGET_NOKERNINFO 0x02000000 /* no kernel output from VSTATUS */
++#define TARGET_PENDIN 0x20000000 /* XXX retype pending input (state) */
++#define TARGET_NOFLSH 0x80000000 /* don't flush after interrupt */
++
++struct target_termios {
++ uint32_t c_iflag; /* input flags */
++ uint32_t c_oflag; /* output flags */
++ uint32_t c_cflag; /* control flags */
++ uint32_t c_lflag; /* local flags */
++ uint8_t c_cc[TARGET_NCCS]; /* control chars */
++ uint32_t c_ispeed; /* input speed */
++ uint32_t c_ospeed; /* output speed */
++};
++
++
++struct target_winsize {
++ uint16_t ws_row; /* rows, in characters */
++ uint16_t ws_col; /* columns, in characters */
++ uint16_t ws_xpixel; /* horizontal size, pixels */
++ uint16_t ws_ypixel; /* vertical size, pixels */
++};
++
++ /* 0-2 compat */
++ /* 3-7 unused */
++ /* 8-10 compat */
++ /* 11-12 unused */
++#define TARGET_TIOCEXCL TARGET_IO('t', 13) /* set exclusive use of tty */
++#define TARGET_TIOCNXCL TARGET_IO('t', 14) /* reset exclusive use of tty */
++#define TARGET_TIOCGPTN TARGET_IOR('t', 15, int) /* Get pts number. */
++#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */
++ /* 17-18 compat */
++/* get termios struct */
++#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios)
++/* set termios struct */
++#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios)
++/* drain output, set */
++#define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct target_termios)
++/* drn out, fls in, set */
++#define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct target_termios)
++ /* 23-25 unused */
++#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */
++#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */
++#define TARGET_TIOCPTMASTER TARGET_IO('t', 28) /* pts master validation */
++ /* 29-85 unused */
++/* get ttywait timeout */
++#define TARGET_TIOCGDRAINWAIT TARGET_IOR('t', 86, int)
++/* set ttywait timeout */
++#define TARGET_TIOCSDRAINWAIT TARGET_IOW('t', 87, int)
++ /* 88 unused */
++ /* 89-91 conflicts: tun and tap */
++/* enable/get timestamp of last input event */
++#define TARGET_TIOCTIMESTAMP TARGET_IOR('t', 89, struct target_timeval)
++/* modem: get wait on close */
++#define TARGET_TIOCMGDTRWAIT TARGET_IOR('t', 90, int)
++/* modem: set wait on close */
++#define TARGET_TIOCMSDTRWAIT TARGET_IOW('t', 91, int)
++ /* 92-93 tun and tap */
++ /* 94-97 conflicts: tun and tap */
++/* wait till output drained */
++#define TARGET_TIOCDRAIN TARGET_IO('t', 94)
++ /* pty: generate signal */
++#define TARGET_TIOCSIG TARGET_IOWINT('t', 95)
++/* pty: external processing */
++#define TARGET_TIOCEXT TARGET_IOW('t', 96, int)
++/* become controlling tty */
++#define TARGET_TIOCSCTTY TARGET_IO('t', 97)
++/* become virtual console */
++#define TARGET_TIOCCONS TARGET_IOW('t', 98, int)
++/* get session id */
++#define TARGET_TIOCGSID TARGET_IOR('t', 99, int)
++ /* 100 unused */
++/* simulate ^T status message */
++#define TARGET_TIOCSTAT TARGET_IO('t', 101)
++ /* pty: set/clr usr cntl mode */
++#define TARGET_TIOCUCNTL TARGET_IOW('t', 102, int)
++/* usr cntl op "n" */
++#define TARGET_TIOCCMD(n) TARGET_IO('u', n)
++/* set window size */
++#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize)
++/* get window size */
++#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize)
++ /* 105 unused */
++/* get all modem bits */
++#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
++#define TARGET_TIOCM_LE 0001 /* line enable */
++#define TARGET_TIOCM_DTR 0002 /* data terminal ready */
++#define TARGET_TIOCM_RTS 0004 /* request to send */
++#define TARGET_TIOCM_ST 0010 /* secondary transmit */
++#define TARGET_TIOCM_SR 0020 /* secondary receive */
++#define TARGET_TIOCM_CTS 0040 /* clear to send */
++#define TARGET_TIOCM_DCD 0100 /* data carrier detect */
++#define TARGET_TIOCM_RI 0200 /* ring indicate */
++#define TARGET_TIOCM_DSR 0400 /* data set ready */
++#define TARGET_TIOCM_CD TARGET_TIOCM_DCD
++#define TARGET_TIOCM_CAR TARGET_TIOCM_DCD
++#define TARGET_TIOCM_RNG TARGET_TIOCM_RI
++#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */
++#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */
++#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */
++/* start output, like ^Q */
++#define TARGET_TIOCSTART TARGET_IO('t', 110)
++/* stop output, like ^S */
++#define TARGET_TIOCSTOP TARGET_IO('t', 111)
++/* pty: set/clear packet mode */
++#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
++#define TARGET_TIOCPKT_DATA 0x00 /* data packet */
++#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */
++#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */
++#define TARGET_TIOCPKT_STOP 0x04 /* stop output */
++#define TARGET_TIOCPKT_START 0x08 /* start output */
++#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */
++#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */
++#define TARGET_TIOCPKT_IOCTL 0x40 /* state change of pty
++ driver */
++#define TARGET_TIOCNOTTY TARGET_IO('t', 113) /* void tty
++ association */
++#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) /* simulate
++ terminal input */
++#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */
++ /* 116-117 compat */
++#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */
++#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */
++#define TARGET_TIOCCDTR TARGET_IO('t', 120) /* clear data terminal
++ ready */
++#define TARGET_TIOCSDTR TARGET_IO('t', 121) /* set data terminal
++ ready */
++#define TARGET_TIOCCBRK TARGET_IO('t', 122) /* clear break bit */
++#define TARGET_TIOCSBRK TARGET_IO('t', 123) /* set break bit */
++ /* 124-127 compat */
++
++#define TARGET_TTYDISC 0 /* termios tty line
++ discipline */
++#define TARGET_SLIPDISC 4 /* serial IP discipline */
++#define TARGET_PPPDISC 5 /* PPP discipline */
++#define TARGET_NETGRAPHDISC 6 /* Netgraph tty node
++ discipline */
++#define TARGET_H4DISC 7 /* Netgraph Bluetooth H4
++ discipline */
++
++#endif /* _FREEBSD_TTYCOM_H_ */
+diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
+index 9d4edbf..e3bcc57 100644
+--- a/bsd-user/qemu.h
++++ b/bsd-user/qemu.h
+@@ -23,6 +23,7 @@ extern enum BSDType bsd_type;
+ abi_long memcpy_to_target(abi_ulong dest, const void *src,
+ unsigned long len);
+
++#include "exec/user/thunk.h"
+ #include "syscall_defs.h"
+ #include "syscall.h"
+ #include "target_vmparam.h"
+diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
+index bde9ee9..89ce296 100644
+--- a/bsd-user/syscall.c
++++ b/bsd-user/syscall.c
+@@ -47,6 +47,12 @@
+ #include <sys/thr.h>
+ #include <sys/rtprio.h>
+ #include <sys/umtx.h>
++#include <sys/uuid.h>
++#include <sys/_termios.h>
++#include <sys/ttycom.h>
++#include <sys/reboot.h>
++#include <sys/timex.h>
++#include <kenv.h>
+ #include <pthread.h>
+ #include <machine/atomic.h>
+ #endif
+@@ -61,6 +67,10 @@
+
+ #include "qemu.h"
+ #include "qemu-common.h"
++#ifdef __FreeBSD__
++#include "freebsd/ttycom.h"
++#endif
++
+
+ //#define DEBUG
+
+@@ -791,7 +801,7 @@ host_to_target_waitstatus(int status)
+ }
+
+ static inline abi_long
+-copy_from_user_timeval(struct timeval *tv, abi_ulong target_tv_addr)
++target_to_host_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+ {
+ struct target_freebsd_timeval *target_tv;
+
+@@ -804,6 +814,33 @@ copy_from_user_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+ }
+
+ static inline abi_long
++target_to_host_timex(struct timex *host_tx, abi_ulong target_tx_addr)
++{
++ struct target_timex *target_tx;
++
++ if (!lock_user_struct(VERIFY_READ, target_tx, target_tx_addr, 0))
++ return (-TARGET_EFAULT);
++ __get_user(host_tx->modes, &target_tx->modes);
++ __get_user(host_tx->offset, &target_tx->offset);
++ __get_user(host_tx->freq, &target_tx->freq);
++ __get_user(host_tx->maxerror, &target_tx->maxerror);
++ __get_user(host_tx->esterror, &target_tx->esterror);
++ __get_user(host_tx->status, &target_tx->status);
++ __get_user(host_tx->constant, &target_tx->constant);
++ __get_user(host_tx->precision, &target_tx->precision);
++ __get_user(host_tx->ppsfreq, &target_tx->ppsfreq);
++ __get_user(host_tx->jitter, &target_tx->jitter);
++ __get_user(host_tx->shift, &target_tx->shift);
++ __get_user(host_tx->stabil, &target_tx->stabil);
++ __get_user(host_tx->jitcnt, &target_tx->jitcnt);
++ __get_user(host_tx->calcnt, &target_tx->calcnt);
++ __get_user(host_tx->errcnt, &target_tx->errcnt);
++ __get_user(host_tx->stbcnt, &target_tx->stbcnt);
++ unlock_user_struct(target_tx, target_tx_addr, 1);
++ return (0);
++}
++
++static inline abi_long
+ target_to_host_timespec(struct timespec *ts, abi_ulong target_ts_addr)
+ {
+ struct target_freebsd_timespec *target_ts;
+@@ -817,7 +854,7 @@ target_to_host_timespec(struct timespec *ts, abi_ulong target_ts_addr)
+ }
+
+ static inline abi_long
+-fbsd_copy_to_user_timeval(struct timeval *tv, abi_ulong target_tv_addr)
++host_to_target_timeval(struct timeval *tv, abi_ulong target_tv_addr)
+ {
+ struct target_freebsd_timeval *target_tv;
+
+@@ -841,6 +878,23 @@ host_to_target_timespec(abi_ulong target_ts_addr, struct timespec *ts)
+ unlock_user_struct(target_ts, target_ts_addr, 1);
+ return (0);
+ }
++
++static inline abi_long
++host_to_target_ntptimeval(abi_ulong target_ntv_addr, struct ntptimeval *ntv)
++{
++ struct target_ntptimeval *target_ntv;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_ntv, target_ntv_addr, 0))
++ return (-TARGET_EFAULT);
++ __put_user(ntv->time.tv_sec, &target_ntv->time.tv_sec);
++ __put_user(ntv->time.tv_nsec, &target_ntv->time.tv_nsec);
++ __put_user(ntv->maxerror, &target_ntv->maxerror);
++ __put_user(ntv->esterror, &target_ntv->esterror);
++ __put_user(ntv->tai, &target_ntv->tai);
++ __put_user(ntv->time_state, &target_ntv->time_state);
++ return (0);
++}
++
+ static inline abi_ulong
+ copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n)
+ {
+@@ -1251,7 +1305,7 @@ do_freebsd_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr,
+ return (ret);
+
+ if (target_tv_addr) {
+- if (copy_from_user_timeval(&tv, target_tv_addr))
++ if (target_to_host_timeval(&tv, target_tv_addr))
+ return (-TARGET_EFAULT);
+ tv_ptr = &tv;
+ } else {
+@@ -1269,7 +1323,7 @@ do_freebsd_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr,
+ return (-TARGET_EFAULT);
+
+ if (target_tv_addr &&
+- fbsd_copy_to_user_timeval(&tv, target_tv_addr))
++ host_to_target_timeval(&tv, target_tv_addr))
+ return (-TARGET_EFAULT);
+ }
+
+@@ -2483,234 +2537,1659 @@ do_thr_set_name(long tid, char *name)
+ #endif /* CONFIG_USE_NPTL */
+
+ static int
+-do_umtx_lock(abi_ulong umtx_addr, uint32_t id)
++tcmpset_al(abi_ulong *addr, abi_ulong a, abi_ulong b)
+ {
+- int ret = 0;
++ abi_ulong current = tswapal(a);
++ abi_ulong new = tswapal(b);
++
++#ifdef TARGET_ABI32
++ return (atomic_cmpset_acq_32(addr, current, new));
++#else
++ return (atomic_cmpset_acq_64(addr, current, new));
++#endif
++}
++
++static int
++tcmpset_32(uint32_t *addr, uint32_t a, uint32_t b)
++{
++ uint32_t current = tswap32(a);
++ uint32_t new = tswap32(b);
++
++ return (atomic_cmpset_acq_32(addr, current, new));
++}
++
++static int
++do_lock_umtx(abi_ulong target_addr, abi_long id, struct timespec *timeout)
++{
++ abi_long owner;
++ int ret;
+
++ /*
++ * XXX Note that memory at umtx_addr can change and so we need to be
++ * careful and check for faults.
++ */
+ for (;;) {
+- ret = get_errno(_umtx_op(g2h(umtx_addr +
+- offsetof(struct target_umtx, u_owner)),
+- UMTX_OP_MUTEX_WAIT, UMTX_UNOWNED, 0, 0));
++ struct target_umtx *target_umtx;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0))
++ return (-TARGET_EFAULT);
++
++ /* Check the simple uncontested case. */
++ if (tcmpset_al(&target_umtx->u_owner,
++ TARGET_UMTX_UNOWNED, id)) {
++ unlock_user_struct(target_umtx, target_addr, 1);
++ return (0);
++ }
++
++ /* Check to see if the lock is contested but free. */
++ __get_user(owner, &target_umtx->u_owner);
++
++ if (TARGET_UMTX_CONTESTED == owner) {
++ if (tcmpset_al(&target_umtx->u_owner,
++ TARGET_UMTX_CONTESTED,
++ id | TARGET_UMTX_CONTESTED)) {
++ unlock_user_struct(target_umtx, target_addr, 1);
++ return (0);
++ }
++
++ /* We failed because it changed on us, restart. */
++ unlock_user_struct(target_umtx, target_addr, 1);
++ continue;
++ }
++
++ /* Set the contested bit and sleep. */
++ do {
++ __get_user(owner, &target_umtx->u_owner);
++ if (owner & TARGET_UMTX_CONTESTED)
++ break;
++ } while (!tcmpset_al(&target_umtx->u_owner, owner,
++ owner | TARGET_UMTX_CONTESTED));
++
++ __get_user(owner, &target_umtx->u_owner);
++ unlock_user_struct(target_umtx, target_addr, 1);
++
++ /* Byte swap, if needed, to match what is stored in user mem. */
++ owner = tswapal(owner);
++#ifdef TARGET_ABI32
++ ret = get_errno(_umtx_op(target_umtx, UMTX_OP_WAIT_UINT, owner,
++ NULL, timeout));
++#else
++ ret = get_errno(_umtx_op(target_umtx, UMTX_OP_WAIT, owner,
++ NULL, timeout));
++#endif
+ 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)
++do_unlock_umtx(abi_ulong target_addr, abi_ulong id)
+ {
+- uint32_t owner;
++ abi_ulong owner;
++ struct target_umtx *target_umtx;
+
+- 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));
++ if (!lock_user_struct(VERIFY_WRITE, target_umtx, target_addr, 0))
++ return (-TARGET_EFAULT);
++
++ __get_user(owner, &target_umtx->u_owner);
++ if ((owner & ~TARGET_UMTX_CONTESTED) != id) {
++ unlock_user_struct(target_umtx, target_addr, 1);
++ return (-TARGET_EPERM);
++ }
++
++ /* Check the simple uncontested case. */
++ if ((owner & ~TARGET_UMTX_CONTESTED) == 0)
++ if (tcmpset_al(&target_umtx->u_owner, owner,
++ TARGET_UMTX_UNOWNED)) {
++ unlock_user_struct(target_umtx, target_addr, 1);
++ return (0);
++ }
++
++ /* This is a contested lock. Unlock it. */
++ __put_user(TARGET_UMTX_UNOWNED, &target_umtx->u_owner);
++ unlock_user_struct(target_umtx, target_addr, 1);
++
++ /* Wake up all those contesting it. */
++ _umtx_op(target_umtx, UMTX_OP_WAKE, 0, 0, 0);
+
+ 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>. */
+-abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+- abi_long arg2, abi_long arg3, abi_long arg4,
+- abi_long arg5, abi_long arg6, abi_long arg7,
+- abi_long arg8)
++static int
++do_lock_umutex(abi_ulong target_addr, uint32_t id, struct timespec *ts,
++ int mode)
+ {
+- abi_long ret;
+- void *p;
+- struct stat st;
++ uint32_t owner, flags;
++ int ret;
+
+-#ifdef DEBUG
+- gemu_log("freebsd syscall %d\n", num);
+-#endif
+- if(do_strace)
+- print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+-
+- switch(num) {
+- case TARGET_FREEBSD_NR_exit:
+-#ifdef TARGET_GPROF
+- _mcleanup();
+-#endif
+- gdb_exit(cpu_env, arg1);
+- /* XXX: should free thread stack and CPU env */
+- _exit(arg1);
+- ret = 0; /* avoid warning */
+- break;
+- case TARGET_FREEBSD_NR_read:
+- if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+- goto efault;
+- ret = get_errno(read(arg1, p, arg3));
+- unlock_user(p, arg2, ret);
+- break;
++ for (;;) {
++ struct target_umutex *target_umutex;
+
+- case TARGET_FREEBSD_NR_readv:
+- {
+- int count = arg3;
+- struct iovec *vec;
++ if (!lock_user_struct(VERIFY_WRITE, target_umutex,
++ target_addr, 0))
++ return (-TARGET_EFAULT);
+
+- vec = alloca(count * sizeof(struct iovec));
+- if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
+- goto efault;
+- ret = get_errno(readv(arg1, vec, count));
+- unlock_iovec(vec, arg2, count, 1);
+- }
+- break;
++ __get_user(owner, &target_umutex->m_owner);
+
+- case TARGET_FREEBSD_NR_pread:
+- if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+- goto efault;
+- ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
+- unlock_user(p, arg2, ret);
+- break;
++ if (TARGET_UMUTEX_WAIT == mode) {
++ if (TARGET_UMUTEX_UNOWNED == owner ||
++ TARGET_UMUTEX_CONTESTED == owner)
++ unlock_user_struct(target_umutex,
++ target_addr, 1);
++ return (0);
++ } else {
++ if (tcmpset_32(&target_umutex->m_owner,
++ TARGET_UMUTEX_UNOWNED, id)) {
++ /* The acquired succeeded. */
++ unlock_user_struct(target_umutex,
++ target_addr, 1);
++ return (0);
++ }
+
+- case TARGET_FREEBSD_NR_preadv:
+- {
+- int count = arg3;
+- struct iovec *vec;
++ /*
++ * If no one owns it but it is contested try to acquire
++ * it.
++ */
++ if (TARGET_UMUTEX_CONTESTED == owner) {
++ if (tcmpset_32(&target_umutex->m_owner,
++ TARGET_UMUTEX_CONTESTED,
++ id | TARGET_UMUTEX_CONTESTED)) {
+
+- vec = alloca(count * sizeof(struct iovec));
+- if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
+- goto efault;
+- ret = get_errno(preadv(arg1, vec, count,
+- target_offset64(arg4, arg5)));
+- unlock_iovec(vec, arg2, count, 1);
+- }
+- break;
++ unlock_user_struct(target_umutex,
++ target_addr, 1);
++ return (0);
++ }
+
+- case TARGET_FREEBSD_NR_write:
+- if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+- goto efault;
+- ret = get_errno(write(arg1, p, arg3));
+- unlock_user(p, arg2, 0);
+- break;
++ /* The lock changed so restart. */
++ unlock_user_struct(target_umutex,
++ target_addr, 1);
++ continue;
++ }
++ }
+
+- case TARGET_FREEBSD_NR_writev:
+- {
+- int count = arg3;
+- struct iovec *vec;
++ __get_user(flags, &target_umutex->m_flags);
++ flags = tswap32(flags);
++ if ((flags & TARGET_UMUTEX_ERROR_CHECK) != 0 &&
++ (owner & ~TARGET_UMUTEX_CONTESTED) == id) {
++ unlock_user_struct(target_umutex, target_addr, 1);
++ return (-TARGET_EDEADLK);
++ }
+
+- vec = alloca(count * sizeof(struct iovec));
+- if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
+- goto efault;
+- ret = get_errno(writev(arg1, vec, count));
+- unlock_iovec(vec, arg2, count, 0);
+- }
+- break;
++ if (TARGET_UMUTEX_TRY == mode) {
++ unlock_user_struct(target_umutex, target_addr, 1);
++ return (-TARGET_EBUSY);
++ }
+
+- case TARGET_FREEBSD_NR_pwrite:
+- if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+- goto efault;
+- ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
+- unlock_user(p, arg2, 0);
+- break;
++ /* Set the contested bit and sleep. */
++ if (!tcmpset_32(&target_umutex->m_owner, owner,
++ owner | TARGET_UMUTEX_CONTESTED)) {
++ unlock_user_struct(target_umutex, target_addr, 1);
++ continue;
++ }
+
+- case TARGET_FREEBSD_NR_pwritev:
+- {
+- int count = arg3;
+- struct iovec *vec;
++ owner = owner | TARGET_UMUTEX_CONTESTED;
++ unlock_user_struct(target_umutex, target_addr, 1);
+
+- vec = alloca(count * sizeof(struct iovec));
+- if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
+- goto efault;
+- ret = get_errno(pwritev(arg1, vec, count,
+- target_offset64(arg4, arg5)));
+- unlock_iovec(vec, arg2, count, 0);
++ /* Byte swap, if needed, to match what is stored in user mem. */
++ owner = tswap32(owner);
++ ret = get_errno(_umtx_op(target_umutex, UMTX_OP_WAIT_UINT, owner,
++ 0, ts));
++ if (ret)
++ return (ret);
+ }
+- break;
+
+- case TARGET_FREEBSD_NR_open:
+- if (!(p = lock_user_string(arg1)))
+- goto efault;
+- ret = get_errno(open(path(p),
+- target_to_host_bitmask(arg2, fcntl_flags_tbl),
+- arg3));
+- unlock_user(p, arg1, 0);
+- break;
++ return (0);
++}
+
+- case TARGET_FREEBSD_NR_openat:
+- if (!(p = lock_user_string(arg2)))
+- goto efault;
+- ret = get_errno(openat(arg1, path(p),
+- target_to_host_bitmask(arg3, fcntl_flags_tbl),
+- arg4));
+- unlock_user(p, arg2, 0);
+- break;
++static int
++do_unlock_umutex(abi_ulong target_addr, uint32_t id)
++{
++ struct target_umutex *target_umutex;
++ uint32_t owner;
+
+- case TARGET_FREEBSD_NR_close:
+- ret = get_errno(close(arg1));
+- break;
+
+- case TARGET_FREEBSD_NR_closefrom:
+- ret = 0;
+- closefrom(arg1);
+- break;
++ if (!lock_user_struct(VERIFY_WRITE, target_umutex, target_addr, 0))
++ return (-TARGET_EFAULT);
+
+-#ifdef TARGET_FREEBSD_NR_creat
+- case TARGET_FREEBSD_NR_creat:
+- if (!(p = lock_user_string(arg1)))
+- goto efault;
+- ret = get_errno(creat(p, arg2));
+- unlock_user(p, arg1, 0);
+- break;
+-#endif
++ /* Make sure we own this mutex. */
++ __get_user(owner, &target_umutex->m_owner);
++ if ((owner & ~TARGET_UMUTEX_CONTESTED) != id) {
++ unlock_user_struct(target_umutex, target_addr, 1);
++ return (-TARGET_EPERM);
++ }
+
+- case TARGET_FREEBSD_NR_mmap:
+- ret = get_errno(target_mmap(arg1, arg2, arg3,
+- target_to_host_bitmask(arg4, mmap_flags_tbl),
+- arg5,
+- arg6));
+- break;
++ if ((owner & TARGET_UMUTEX_CONTESTED) == 0)
++ if (tcmpset_32(&target_umutex->m_owner, owner,
++ TARGET_UMTX_UNOWNED)) {
++ unlock_user_struct(target_umutex, target_addr, 1);
++ return (0);
++ }
+
+- case TARGET_FREEBSD_NR_munmap:
+- ret = get_errno(target_munmap(arg1, arg2));
+- break;
++ /* This is a contested lock. Unlock it. */
++ __put_user(TARGET_UMUTEX_UNOWNED, &target_umutex->m_owner);
++ unlock_user_struct(target_umutex, target_addr, 1);
+
+- case TARGET_FREEBSD_NR_mprotect:
+- ret = get_errno(target_mprotect(arg1, arg2, arg3));
+- break;
++ /* And wake up all those contesting it. */
++ return ( _umtx_op(g2h(target_addr), UMTX_OP_WAKE, 0, 0, 0));
++}
+
+- case TARGET_FREEBSD_NR_msync:
+- ret = get_errno(msync(g2h(arg1), arg2, arg3));
+- break;
++/*
++ * _cv_mutex is keeps other threads from doing a signal or broadcast until
++ * the thread is actually asleep and ready. This is a global mutex for all
++ * condition vars so I am sure performance may be a problem if there are lots
++ * of CVs.
++ */
++static struct umutex _cv_mutex = {0,0,{0,0},{0,0,0,0}};
+
+- case TARGET_FREEBSD_NR_mlock:
+- ret = get_errno(mlock(g2h(arg1), arg2));
+- break;
+
+- case TARGET_FREEBSD_NR_munlock:
+- ret = get_errno(munlock(g2h(arg1), arg2));
+- break;
++/*
++ * wflags CVWAIT_CHECK_UNPARKING, CVWAIT_ABSTIME, CVWAIT_CLOCKID
++ */
++static int
++do_cv_wait(abi_ulong target_ucond_addr, abi_ulong target_umtx_addr,
++ struct timespec *ts, int wflags)
++{
++ long tid;
++ int ret;
+
+- case TARGET_FREEBSD_NR_mlockall:
+- ret = get_errno(mlockall(arg1));
+- break;
++ if (! access_ok(VERIFY_WRITE, target_ucond_addr,
++ sizeof(struct target_ucond))) {
+
+- case TARGET_FREEBSD_NR_munlockall:
+- ret = get_errno(munlockall());
+- break;
++ return (-TARGET_EFAULT);
++ }
+
+- case TARGET_FREEBSD_NR_madvise:
+- /*
+- * A straight passthrough may not be safe because qemu sometimes
+- * turns private file-backed mapping into anonymous mappings. This
+- * will break MADV_DONTNEED. This is a hint, so ignoring and returing
+- * success is ok.
+- */
+- ret = get_errno(0);
+- break;
++ /* Check the clock ID if needed. */
++ if ((wflags & TARGET_CVWAIT_CLOCKID) != 0) {
++ struct target_ucond *target_ucond;
++ uint32_t clockid;
+
+- case TARGET_FREEBSD_NR_break:
++ if (!lock_user_struct(VERIFY_WRITE, target_ucond,
++ target_ucond_addr, 0))
++ return (-TARGET_EFAULT);
++ __get_user(clockid, &target_ucond->c_clockid);
++ unlock_user_struct(target_ucond, target_ucond_addr, 1);
++ if (clockid < CLOCK_REALTIME ||
++ clockid >= CLOCK_THREAD_CPUTIME_ID) {
++ /* Only HW clock id will work. */
++ return (-TARGET_EINVAL);
++ }
++ }
++
++ thr_self(&tid);
++
++ /* Lock the _cv_mutex so we can safely unlock the user mutex */
++ _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
++
++ /* unlock the user mutex */
++ ret = do_unlock_umutex(target_umtx_addr, tid);
++ if (ret) {
++ _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
++ return (ret);
++ }
++
++ /* UMTX_OP_CV_WAIT unlocks _cv_mutex */
++ ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_WAIT,
++ wflags, &_cv_mutex, ts));
++
++ return (ret);
++}
++
++static int
++do_cv_signal(abi_ulong target_ucond_addr)
++{
++ int ret;
++
++ if (! access_ok(VERIFY_WRITE, target_ucond_addr,
++ sizeof(struct target_ucond)))
++ return (-TARGET_EFAULT);
++
++ /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
++ _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
++ ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_SIGNAL, 0,
++ NULL, NULL));
++ _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
++
++ return (ret);
++}
++
++static int
++do_cv_broadcast(abi_ulong target_ucond_addr)
++{
++ int ret;
++
++ if (! access_ok(VERIFY_WRITE, target_ucond_addr,
++ sizeof(struct target_ucond)))
++ return (-TARGET_EFAULT);
++
++ /* Lock the _cv_mutex to prevent a race in do_cv_wait(). */
++ _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_LOCK, 0, NULL, NULL);
++ ret = get_errno(_umtx_op(g2h(target_ucond_addr), UMTX_OP_CV_BROADCAST,
++ 0, NULL, NULL));
++ _umtx_op(&_cv_mutex, UMTX_OP_MUTEX_UNLOCK, 0, NULL, NULL);
++
++ return (ret);
++}
++
++static int
++do_umtx_op_wait(abi_ulong target_addr, abi_ulong id, struct timespec *ts)
++{
++
++ /* We want to check the user memory but not lock it. We might sleep. */
++ if (! access_ok(VERIFY_READ, target_addr, sizeof(abi_ulong)))
++ return (-TARGET_EFAULT);
++
++ /* id has already been byte swapped to match what may be in user mem. */
++#ifdef TARGET_ABI32
++ return (get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAIT_UINT, id, NULL,
++ ts)));
++#else
++ return (get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAIT, id, NULL,
++ ts)));
++#endif
++}
++
++static int
++do_umtx_op_wake(abi_ulong target_addr, abi_ulong n_wake)
++{
++
++ return (get_errno(_umtx_op(g2h(target_addr), UMTX_OP_WAKE, n_wake, NULL,
++ 0)));
++}
++
++static int
++do_rw_rdlock(abi_ulong target_addr, long fflag, struct timespec *ts)
++{
++ struct target_urwlock *target_urwlock;
++ uint32_t flags, wrflags;
++ uint32_t state;
++ uint32_t blocked_readers;
++ int ret;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0))
++ return (-TARGET_EFAULT);
++
++ __get_user(flags, &target_urwlock->rw_flags);
++ wrflags = TARGET_URWLOCK_WRITE_OWNER;
++ if (!(fflag & TARGET_URWLOCK_PREFER_READER) &&
++ !(flags & TARGET_URWLOCK_PREFER_READER))
++ wrflags |= TARGET_URWLOCK_WRITE_WAITERS;
++
++ for (;;) {
++ __get_user(state, &target_urwlock->rw_state);
++ /* try to lock it */
++ while (!(state & wrflags)) {
++ if (TARGET_URWLOCK_READER_COUNT(state) ==
++ TARGET_URWLOCK_MAX_READERS) {
++ unlock_user_struct(target_urwlock,
++ target_addr, 1);
++ return (-TARGET_EAGAIN);
++ }
++ if (tcmpset_32(&target_urwlock->rw_state, state,
++ (state + 1))) {
++ /* The acquired succeeded. */
++ unlock_user_struct(target_urwlock,
++ target_addr, 1);
++ return (0);
++ }
++ __get_user(state, &target_urwlock->rw_state);
++ }
++
++ /* set read contention bit */
++ if (! tcmpset_32(&target_urwlock->rw_state, state,
++ state | TARGET_URWLOCK_READ_WAITERS)) {
++ /* The state has changed. Start over. */
++ continue;
++ }
++
++ /* contention bit is set, increase read waiter count */
++ __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
++ while (! tcmpset_32(&target_urwlock->rw_blocked_readers,
++ blocked_readers, blocked_readers + 1)) {
++ __get_user(blocked_readers,
++ &target_urwlock->rw_blocked_readers);
++ }
++
++ while (state & wrflags) {
++ /* sleep/wait */
++ unlock_user_struct(target_urwlock, target_addr, 1);
++ ret = get_errno(_umtx_op(
++ &target_urwlock->rw_blocked_readers,
++ UMTX_OP_WAIT_UINT, blocked_readers, 0, ts));
++ if (ret)
++ return (ret);
++ if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
++ target_addr, 0))
++ return (-TARGET_EFAULT);
++ __get_user(state, &target_urwlock->rw_state);
++ }
++
++ /* decrease read waiter count */
++ __get_user(blocked_readers, &target_urwlock->rw_blocked_readers);
++ while (! tcmpset_32(&target_urwlock->rw_blocked_readers,
++ blocked_readers, (blocked_readers - 1))) {
++ __get_user(blocked_readers,
++ &target_urwlock->rw_blocked_readers);
++ }
++ if (1 == blocked_readers) {
++ /* clear read contention bit */
++ __get_user(state, &target_urwlock->rw_state);
++ while(! tcmpset_32(&target_urwlock->rw_state, state,
++ state & ~TARGET_URWLOCK_READ_WAITERS)) {
++ __get_user(state, &target_urwlock->rw_state);
++ }
++ }
++ }
++}
++
++static int
++do_rw_wrlock(abi_ulong target_addr, long fflag, struct timespec *ts)
++{
++ struct target_urwlock *target_urwlock;
++ uint32_t blocked_readers, blocked_writers;
++ uint32_t state;
++ int ret;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0))
++ return (-TARGET_EFAULT);
++
++ blocked_readers = 0;
++ for (;;) {
++ __get_user(state, &target_urwlock->rw_state);
++ while (!(state & TARGET_URWLOCK_WRITE_OWNER) &&
++ TARGET_URWLOCK_READER_COUNT(state) == 0) {
++ if (tcmpset_32(&target_urwlock->rw_state, state,
++ state | TARGET_URWLOCK_WRITE_OWNER)) {
++ unlock_user_struct(target_urwlock,
++ target_addr, 1);
++ return (0);
++ }
++ __get_user(state, &target_urwlock->rw_state);
++ }
++
++ if (!(state & (TARGET_URWLOCK_WRITE_OWNER |
++ TARGET_URWLOCK_WRITE_WAITERS)) &&
++ blocked_readers != 0) {
++ ret = get_errno(_umtx_op(
++ &target_urwlock->rw_blocked_readers,
++ UMTX_OP_WAKE, INT_MAX, NULL, NULL));
++ return (ret);
++ }
++
++ /* re-read the state */
++ __get_user(state, &target_urwlock->rw_state);
++
++ /* and set TARGET_URWLOCK_WRITE_WAITERS */
++ while (((state & TARGET_URWLOCK_WRITE_OWNER) ||
++ TARGET_URWLOCK_READER_COUNT(state) != 0) &&
++ (state & TARGET_URWLOCK_WRITE_WAITERS) == 0) {
++ if (tcmpset_32(&target_urwlock->rw_state, state,
++ state | TARGET_URWLOCK_WRITE_WAITERS)) {
++ break;
++ }
++ __get_user(state, &target_urwlock->rw_state);
++ }
++
++ /* contention bit is set, increase write waiter count */
++ __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
++ while (! tcmpset_32(&target_urwlock->rw_blocked_writers,
++ blocked_writers, blocked_writers + 1)) {
++ __get_user(blocked_writers,
++ &target_urwlock->rw_blocked_writers);
++ }
++
++ /* sleep */
++ while ((state & TARGET_URWLOCK_WRITE_OWNER) ||
++ (TARGET_URWLOCK_READER_COUNT(state) != 0)) {
++ unlock_user_struct(target_urwlock, target_addr, 1);
++ ret = get_errno(_umtx_op(
++ &target_urwlock->rw_blocked_writers,
++ UMTX_OP_WAIT_UINT, blocked_writers, 0, ts));
++ if (ret)
++ return (ret);
++ if (!lock_user_struct(VERIFY_WRITE, target_urwlock,
++ target_addr, 0))
++ return (-TARGET_EFAULT);
++ __get_user(state, &target_urwlock->rw_state);
++ }
++
++ /* decrease the write waiter count */
++ __get_user(blocked_writers, &target_urwlock->rw_blocked_writers);
++ while (! tcmpset_32(&target_urwlock->rw_blocked_writers,
++ blocked_writers, (blocked_writers - 1))) {
++ __get_user(blocked_writers,
++ &target_urwlock->rw_blocked_writers);
++ }
++ if (1 == blocked_writers) {
++ /* clear write contention bit */
++ __get_user(state, &target_urwlock->rw_state);
++ while(! tcmpset_32(&target_urwlock->rw_state, state,
++ state & ~TARGET_URWLOCK_WRITE_WAITERS)) {
++ __get_user(state, &target_urwlock->rw_state);
++ }
++ __get_user(blocked_readers,
++ &target_urwlock->rw_blocked_readers);
++ } else
++ blocked_readers = 0;
++ }
++}
++
++static int
++do_rw_unlock(abi_ulong target_addr)
++{
++ struct target_urwlock *target_urwlock;
++ uint32_t flags, state, count;
++ void *q = NULL;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_urwlock, target_addr, 0))
++ return (-TARGET_EFAULT);
++
++ __get_user(flags, &target_urwlock->rw_flags);
++ __get_user(state, &target_urwlock->rw_state);
++
++ if (state & TARGET_URWLOCK_WRITE_OWNER) {
++ for (;;) {
++ if (! tcmpset_32(&target_urwlock->rw_state, state,
++ state & ~TARGET_URWLOCK_WRITE_OWNER)) {
++ __get_user(state, &target_urwlock->rw_state);
++ if (!(state & TARGET_URWLOCK_WRITE_OWNER)) {
++ unlock_user_struct(target_urwlock,
++ target_addr, 1);
++ return (-TARGET_EPERM);
++ }
++ } else
++ break;
++ }
++ } else if (TARGET_URWLOCK_READER_COUNT(state) != 0) {
++ /* decrement reader count */
++ for (;;) {
++ if (! tcmpset_32(&target_urwlock->rw_state,
++ state, (state - 1))) {
++ if (TARGET_URWLOCK_READER_COUNT(state) == 0) {
++ unlock_user_struct(target_urwlock,
++ target_addr, 1);
++ return (-TARGET_EPERM);
++ }
++ } else
++ break;
++ }
++ } else {
++ unlock_user_struct(target_urwlock, target_addr, 1);
++ return (-TARGET_EPERM);
++ }
++
++ count = 0;
++
++ if (! (flags & TARGET_URWLOCK_PREFER_READER)) {
++ if (state & TARGET_URWLOCK_WRITE_WAITERS) {
++ count = 1;
++ q = &target_urwlock->rw_blocked_writers;
++ } else if (state & TARGET_URWLOCK_READ_WAITERS) {
++ count = INT_MAX;
++ q = &target_urwlock->rw_blocked_readers;
++ }
++ } else {
++ if (state & TARGET_URWLOCK_READ_WAITERS) {
++ count = INT_MAX;
++ q = &target_urwlock->rw_blocked_readers;
++ } else if (state & TARGET_URWLOCK_WRITE_WAITERS) {
++ count = 1;
++ q = &target_urwlock->rw_blocked_writers;
++ }
++ }
++
++ unlock_user_struct(target_urwlock, target_addr, 1);
++ if (q != NULL)
++ return (get_errno(_umtx_op(q, UMTX_OP_WAKE, count, NULL, NULL)));
++ else
++ return (0);
++}
++
++static inline abi_long
++target_to_host_statfs(struct statfs *host_statfs, abi_ulong target_addr)
++{
++ struct target_statfs *target_statfs;
++
++ if (!lock_user_struct(VERIFY_READ, target_statfs, target_addr, 1))
++ return (-TARGET_EFAULT);
++ __get_user(host_statfs->f_version, &target_statfs->f_version);
++ __get_user(host_statfs->f_type, &target_statfs->f_type);
++ __get_user(host_statfs->f_flags, &target_statfs->f_flags);
++ __get_user(host_statfs->f_bsize, &target_statfs->f_bsize);
++ __get_user(host_statfs->f_iosize, &target_statfs->f_iosize);
++ __get_user(host_statfs->f_blocks, &target_statfs->f_blocks);
++ __get_user(host_statfs->f_bfree, &target_statfs->f_bfree);
++ __get_user(host_statfs->f_bavail, &target_statfs->f_bavail);
++ __get_user(host_statfs->f_files, &target_statfs->f_files);
++ __get_user(host_statfs->f_ffree, &target_statfs->f_ffree);
++ __get_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
++ __get_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
++ __get_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
++ __get_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
++ /* uint64_t f_spare[10]; */
++ __get_user(host_statfs->f_namemax, &target_statfs->f_namemax);
++ __get_user(host_statfs->f_owner, &target_statfs->f_owner);
++ __get_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
++ __get_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
++ /* char f_charspace[80]; */
++ strncpy(host_statfs->f_fstypename, &target_statfs->f_fstypename[0],
++ TARGET_MFSNAMELEN);
++ strncpy(host_statfs->f_mntfromname, &target_statfs->f_mntfromname[0],
++ TARGET_MNAMELEN);
++ strncpy(host_statfs->f_mntonname, &target_statfs->f_mntonname[0],
++ TARGET_MNAMELEN);
++ unlock_user_struct(target_statfs, target_addr, 0);
++ return (0);
++}
++
++static inline abi_long
++host_to_target_statfs(abi_ulong target_addr, struct statfs *host_statfs)
++{
++ struct target_statfs *target_statfs;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0))
++ return (-TARGET_EFAULT);
++ __put_user(host_statfs->f_version, &target_statfs->f_version);
++ __put_user(host_statfs->f_type, &target_statfs->f_type);
++ __put_user(host_statfs->f_flags, &target_statfs->f_flags);
++ __put_user(host_statfs->f_bsize, &target_statfs->f_bsize);
++ __put_user(host_statfs->f_iosize, &target_statfs->f_iosize);
++ __put_user(host_statfs->f_blocks, &target_statfs->f_blocks);
++ __put_user(host_statfs->f_bfree, &target_statfs->f_bfree);
++ __put_user(host_statfs->f_bavail, &target_statfs->f_bavail);
++ __put_user(host_statfs->f_files, &target_statfs->f_files);
++ __put_user(host_statfs->f_ffree, &target_statfs->f_ffree);
++ __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites);
++ __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites);
++ __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads);
++ __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads);
++ /* uint64_t f_spare[10]; */
++ __put_user(host_statfs->f_namemax, &target_statfs->f_namemax);
++ __put_user(host_statfs->f_owner, &target_statfs->f_owner);
++ __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]);
++ __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]);
++ /* char f_charspace[80]; */
++ strncpy(&target_statfs->f_fstypename[0], host_statfs->f_fstypename,
++ TARGET_MFSNAMELEN);
++ strncpy(&target_statfs->f_mntfromname[0], host_statfs->f_mntfromname,
++ TARGET_MNAMELEN);
++ strncpy(&target_statfs->f_mntonname[0], host_statfs->f_mntonname,
++ TARGET_MNAMELEN);
++ unlock_user_struct(target_statfs, target_addr, 1);
++ return (0);
++}
++
++static inline abi_long
++target_to_host_fhandle(fhandle_t *host_fh, abi_ulong target_addr)
++{
++ target_fhandle_t *target_fh;
++
++ if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1))
++ return (-TARGET_EFAULT);
++ __get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
++ __get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
++
++ __get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
++ /* u_short fid_data0; */
++ memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data,
++ TARGET_MAXFIDSZ);
++ unlock_user_struct(target_fh, target_addr, 0);
++ return (0);
++}
++
++static inline abi_long
++host_to_target_fhandle(abi_ulong target_addr, fhandle_t *host_fh)
++{
++ target_fhandle_t *target_fh;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0))
++ return (-TARGET_EFAULT);
++ __put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]);
++ __put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]);
++
++ __put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len);
++ /* u_short fid_data0; */
++ memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data,
++ TARGET_MAXFIDSZ);
++ unlock_user_struct(target_fh, target_addr, 1);
++ return (0);
++}
++
++static inline abi_long
++target_to_host_sched_param(struct sched_param *host_sp, abi_ulong target_addr)
++{
++ struct target_sched_param *target_sp;
++
++ if (!lock_user_struct(VERIFY_READ, target_sp, target_addr, 1))
++ return (-TARGET_EFAULT);
++ __get_user(host_sp->sched_priority, &target_sp->sched_priority);
++ unlock_user_struct(target_sp, target_addr, 0);
++ return (0);
++}
++
++static inline abi_long
++host_to_target_sched_param(abi_ulong target_addr, struct sched_param *host_sp)
++{
++ struct target_sched_param *target_sp;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_sp, target_addr, 0))
++ return (-TARGET_EFAULT);
++ __put_user(host_sp->sched_priority, &target_sp->sched_priority);
++ unlock_user_struct(target_sp, target_addr, 1);
++ return (0);
++}
++
++static inline abi_long
++do_sched_setparam(pid_t pid, abi_ulong target_sp_addr)
++{
++ int ret;
++ struct sched_param host_sp;
++
++ ret = target_to_host_sched_param(&host_sp, target_sp_addr);
++ if (0 == ret)
++ ret = get_errno(sched_setparam(pid, &host_sp));
++
++ return (ret);
++}
++
++static inline abi_long
++do_sched_getparam(pid_t pid, abi_ulong target_sp_addr)
++{
++ int ret;
++ struct sched_param host_sp;
++
++ ret = get_errno(sched_getparam(pid, &host_sp));
++ if (0 == ret)
++ ret = host_to_target_sched_param(target_sp_addr, &host_sp);
++
++ return (ret);
++}
++
++static inline abi_long
++do_sched_setscheduler(pid_t pid, int policy, abi_ulong target_sp_addr)
++{
++ int ret;
++ struct sched_param host_sp;
++
++ ret = target_to_host_sched_param(&host_sp, target_sp_addr);
++ if (0 == ret)
++ ret = get_errno(sched_setscheduler(pid, policy, &host_sp));
++
++ return (ret);
++}
++
++static inline abi_long
++do_sched_rr_get_interval(pid_t pid, abi_ulong target_ts_addr)
++{
++ int ret;
++ struct timespec host_ts;
++
++ ret = get_errno(sched_rr_get_interval(pid, &host_ts));
++ if (0 == ret)
++ ret = host_to_target_timespec(target_ts_addr, &host_ts);
++
++ return (ret);
++}
++
++static inline abi_long
++host_to_target_uuid(abi_ulong target_addr, struct uuid *host_uuid)
++{
++ struct target_uuid *target_uuid;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_uuid, target_addr, 0))
++ return (-TARGET_EFAULT);
++ __put_user(host_uuid->time_low, &target_uuid->time_low);
++ __put_user(host_uuid->time_mid, &target_uuid->time_mid);
++ __put_user(host_uuid->time_hi_and_version,
++ &target_uuid->time_hi_and_version);
++ host_uuid->clock_seq_hi_and_reserved =
++ target_uuid->clock_seq_hi_and_reserved;
++ host_uuid->clock_seq_low = target_uuid->clock_seq_low;
++ memcpy(host_uuid->node, target_uuid->node, TARGET_UUID_NODE_LEN);
++ unlock_user_struct(target_uuid, target_addr, 1);
++ return (0);
++}
++
++static inline abi_long
++host_to_target_stat(abi_ulong target_addr, struct stat *host_st)
++{
++ struct target_freebsd_stat *target_st;
++
++ if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
++ return (-TARGET_EFAULT);
++ memset(target_st, 0, sizeof(*target_st));
++ __put_user(host_st->st_dev, &target_st->st_dev);
++ __put_user(host_st->st_ino, &target_st->st_ino);
++ __put_user(host_st->st_mode, &target_st->st_mode);
++ __put_user(host_st->st_nlink, &target_st->st_nlink);
++ __put_user(host_st->st_uid, &target_st->st_uid);
++ __put_user(host_st->st_gid, &target_st->st_gid);
++ __put_user(host_st->st_rdev, &target_st->st_rdev);
++ __put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec);
++ __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
++ __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
++ __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
++ __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
++ __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
++ __put_user(host_st->st_size, &target_st->st_size);
++ __put_user(host_st->st_blocks, &target_st->st_blocks);
++ __put_user(host_st->st_blksize, &target_st->st_blksize);
++ __put_user(host_st->st_flags, &target_st->st_flags);
++ __put_user(host_st->st_gen, &target_st->st_gen);
++ /* st_lspare not used */
++ __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec);
++ __put_user(host_st->st_birthtim.tv_nsec,
++ &target_st->st_birthtim.tv_nsec);
++ unlock_user_struct(target_st, target_addr, 1);
++
++ return (0);
++}
++
++static inline abi_long
++do_getfh(const char *path, abi_ulong target_addr)
++{
++ abi_long ret;
++ fhandle_t host_fh;
++
++ ret = get_errno(getfh(path, &host_fh));
++ if (ret)
++ return (ret);
++
++ return (host_to_target_fhandle(target_addr, &host_fh));
++}
++
++static inline abi_long
++do_lgetfh(const char *path, abi_ulong target_addr)
++{
++ abi_long ret;
++ fhandle_t host_fh;
++
++ ret = get_errno(lgetfh(path, &host_fh));
++ if (ret)
++ return (ret);
++
++ return (host_to_target_fhandle(target_addr, &host_fh));
++}
++
++static inline abi_long
++do_fhopen(abi_ulong target_addr, int flags)
++{
++ abi_long ret;
++ fhandle_t host_fh;
++
++ ret = target_to_host_fhandle(&host_fh, target_addr);
++ if (ret)
++ return (ret);
++
++ return (get_errno(fhopen(&host_fh, flags)));
++}
++
++static inline abi_long
++do_fhstat(abi_ulong target_fhp_addr, abi_ulong target_sb_addr)
++{
++ abi_long ret;
++ fhandle_t host_fh;
++ struct stat host_sb;
++
++ ret = target_to_host_fhandle(&host_fh, target_fhp_addr);
++ if (ret)
++ return (ret);
++
++ ret = get_errno(fhstat(&host_fh, &host_sb));
++ if (ret)
++ return (ret);
++
++ return (host_to_target_stat(target_sb_addr, &host_sb));
++}
++
++static inline abi_long
++do_fhstatfs(abi_ulong target_fhp_addr, abi_ulong target_stfs_addr)
++{
++ abi_long ret;
++ fhandle_t host_fh;
++ struct statfs host_stfs;
++
++ ret = target_to_host_fhandle(&host_fh, target_fhp_addr);
++ if (ret)
++ return (ret);
++
++ ret = get_errno(fhstatfs(&host_fh, &host_stfs));
++ if (ret)
++ return (ret);
++
++ return (host_to_target_statfs(target_stfs_addr, &host_stfs));
++}
++
++static inline abi_long
++do_statfs(const char *path, abi_ulong target_addr)
++{
++ abi_long ret;
++ struct statfs host_stfs;
++
++ ret = get_errno(statfs(path, &host_stfs));
++ if (ret)
++ return (ret);
++
++ return (host_to_target_statfs(target_addr, &host_stfs));
++}
++
++static inline abi_long
++do_fstatfs(int fd, abi_ulong target_addr)
++{
++ abi_long ret;
++ struct statfs host_stfs;
++
++ ret = get_errno(fstatfs(fd, &host_stfs));
++ if (ret)
++ return (ret);
++
++ return (host_to_target_statfs(target_addr, &host_stfs));
++}
++
++static inline abi_long
++do_getfsstat(abi_ulong target_addr, abi_long bufsize, int flags)
++{
++ abi_long ret;
++ struct statfs *host_stfs;
++ int count;
++ long host_bufsize;
++
++ count = bufsize / sizeof(struct target_statfs);
++
++ /* if user buffer is NULL then return number of mounted FS's */
++ if (0 == target_addr || 0 == count)
++ return (get_errno(getfsstat(NULL, 0, flags)));
++
++ /* XXX check count to be reasonable */
++ host_bufsize = sizeof(struct statfs) * count;
++ host_stfs = alloca(host_bufsize);
++ if (! host_stfs)
++ return (-TARGET_EINVAL);
++
++ ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
++ if (ret < 0)
++ return (ret);
++
++ while (count--)
++ if (host_to_target_statfs(
++ (target_addr + (count * sizeof(struct target_statfs))),
++ &host_stfs[count]))
++ return (-TARGET_EFAULT);
++
++ return (ret);
++}
++
++static abi_long
++do_uuidgen(abi_ulong target_addr, int count)
++{
++ int i;
++ abi_long ret;
++ struct uuid *host_uuid;
++
++ if (count < 1 || count > 2048)
++ return (-TARGET_EINVAL);
++
++ host_uuid = (struct uuid *)g_malloc(count * sizeof(struct uuid));
++
++ if (NULL == host_uuid)
++ return (-TARGET_EINVAL);
++
++ ret = get_errno(uuidgen(host_uuid, count));
++ if (ret)
++ goto out;
++ for(i = 0; i < count; i++) {
++ ret = host_to_target_uuid(target_addr +
++ (abi_ulong)(sizeof(struct target_uuid) * i), &host_uuid[i]);
++ if (ret)
++ goto out;
++ }
++
++out:
++ g_free(host_uuid);
++ return (ret);
++}
++
++static abi_long
++do_adjtime(abi_ulong target_delta_addr, abi_ulong target_old_addr)
++{
++ abi_long ret;
++ struct timeval host_delta, host_old;
++
++ ret = target_to_host_timeval(&host_delta, target_delta_addr);
++ if (ret)
++ goto out;
++
++ if (target_old_addr) {
++ ret = get_errno(adjtime(&host_delta, &host_old));
++ if (ret)
++ goto out;
++ ret = host_to_target_timeval(&host_old, target_old_addr);
++ } else
++ ret = get_errno(adjtime(&host_delta, NULL));
++
++out:
++ return (ret);
++}
++
++static abi_long
++do_ntp_adjtime(abi_ulong target_tx_addr)
++{
++ abi_long ret;
++ struct timex host_tx;
++
++ ret = target_to_host_timex(&host_tx, target_tx_addr);
++ if (ret)
++ goto out;
++
++ ret = get_errno(ntp_adjtime(&host_tx));
++
++out:
++ return (ret);
++}
++
++static abi_long
++do_ntp_gettime(abi_ulong target_ntv_addr)
++{
++ abi_long ret;
++ struct ntptimeval host_ntv;
++
++ ret = get_errno(ntp_gettime(&host_ntv));
++ if (ret)
++ goto out;
++
++ ret = host_to_target_ntptimeval(target_ntv_addr, &host_ntv);
++out:
++ return (ret);
++}
++
++/*
++ * ioctl()
++ */
++
++static const bitmask_transtbl iflag_tbl[] = {
++ { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
++ { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
++ { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
++ { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
++ { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
++ { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
++ { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
++ { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
++ { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
++ { TARGET_IXON, TARGET_IXON, IXON, IXON },
++ { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
++#ifdef IXANY
++ { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
++#endif
++#ifdef IMAXBEL
++ { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
++#endif
++ { 0, 0, 0, 0 }
++};
++
++static const bitmask_transtbl oflag_tbl[] = {
++ { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
++#ifdef ONLCR
++ { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
++#endif
++#ifdef TABDLY
++ { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
++ { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
++#endif
++#ifdef ONOEOT
++ { TARGET_ONOEOT, TARGET_ONOEOT, ONOEOT, ONOEOT },
++#endif
++#ifdef OCRNL
++ { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
++#endif
++#ifdef ONOCR
++ { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
++#endif
++#ifdef ONLRET
++ { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
++#endif
++ { 0, 0, 0, 0 }
++};
++
++static const bitmask_transtbl cflag_tbl[] = {
++#ifdef CIGNORE
++ { TARGET_CIGNORE, TARGET_CIGNORE, CIGNORE, CIGNORE },
++#endif
++ { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
++ { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
++ { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
++ { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
++ { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
++ { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
++ { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
++ { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
++ { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
++ { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
++#ifdef CCTS_OFLOW
++ { TARGET_CCTS_OFLOW, TARGET_CCTS_OFLOW, CCTS_OFLOW, CCTS_OFLOW },
++#endif
++#ifdef CRTSCTS
++ { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
++#endif
++#ifdef CRTS_IFLOW
++ { TARGET_CRTS_IFLOW, TARGET_CRTS_IFLOW, CRTS_IFLOW, CRTS_IFLOW },
++#endif
++#ifdef CDTS_IFLOW
++ { TARGET_CDTR_IFLOW, TARGET_CDTR_IFLOW, CDTR_IFLOW, CDTR_IFLOW },
++#endif
++#ifdef CDSR_OFLOW
++ { TARGET_CDSR_OFLOW, TARGET_CDSR_OFLOW, CDSR_OFLOW, CDSR_OFLOW },
++#endif
++#ifdef CCAR_OFLOW
++ { TARGET_CCAR_OFLOW, TARGET_CCAR_OFLOW, CCAR_OFLOW, CCAR_OFLOW },
++#endif
++ { 0, 0, 0, 0 }
++};
++
++static const bitmask_transtbl lflag_tbl[] = {
++#ifdef ECHOKE
++ { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
++#endif
++ { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
++ { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
++ { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
++ { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
++#ifdef ECHOPRT
++ { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
++#endif
++#ifdef ECHOCTL
++ { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
++#endif
++ { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
++ { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
++#ifdef ALTWERASE
++ { TARGET_ALTWERASE, TARGET_ALTWERASE, ALTWERASE, ALTWERASE },
++#endif
++ { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
++ { TARGET_EXTPROC, TARGET_EXTPROC, EXTPROC, EXTPROC },
++ { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
++#ifdef FLUSHO
++ { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
++#endif
++#ifdef NOKERNINFO
++ { TARGET_NOKERNINFO, TARGET_NOKERNINFO, NOKERNINFO, NOKERNINFO },
++#endif
++#ifdef PENDIN
++ { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
++#endif
++ { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
++ { 0, 0, 0, 0 }
++};
++
++static void
++target_to_host_termios(void *dst, const void *src)
++{
++ struct termios *host = dst;
++ const struct target_termios *target = src;
++
++ host->c_iflag =
++ target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
++ host->c_oflag =
++ target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
++ host->c_cflag =
++ target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
++ host->c_lflag =
++ target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
++
++ memset(host->c_cc, 0, sizeof(host->c_cc));
++ host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
++ host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
++#ifdef VEOL2
++ host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
++#endif
++ host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
++#ifdef VWERASE
++ host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
++#endif
++ host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
++#ifdef VREPRINT
++ host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
++#endif
++#ifdef VERASE2
++ host->c_cc[VERASE2] = target->c_cc[TARGET_VERASE2];
++#endif
++ host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
++ host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
++ host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
++#ifdef VDSUSP
++ host->c_cc[VDSUSP] = target->c_cc[TARGET_VDSUSP];
++#endif
++ host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
++ host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
++#ifdef VLNEXT
++ host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
++#endif
++#ifdef VDISCARD
++ host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
++#endif
++ host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
++ host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
++#ifdef VSTATUS
++ host->c_cc[VSTATUS] = target->c_cc[TARGET_VSTATUS];
++#endif
++
++ host->c_ispeed = tswap32(target->c_ispeed);
++ host->c_ospeed = tswap32(target->c_ospeed);
++}
++
++static void
++host_to_target_termios(void *dst, const void *src)
++{
++ struct target_termios *target = dst;
++ const struct termios *host = src;
++
++ target->c_iflag =
++ tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
++ target->c_oflag =
++ tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
++ target->c_cflag =
++ tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
++ target->c_lflag =
++ tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
++
++ memset(target->c_cc, 0, sizeof(target->c_cc));
++ target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
++ target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
++#ifdef VEOL2
++ target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
++#endif
++ target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
++#ifdef VWERASE
++ target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
++#endif
++ target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
++#ifdef VREPRINT
++ target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
++#endif
++#ifdef VERASE2
++ target->c_cc[TARGET_VERASE2] = host->c_cc[VERASE2];
++#endif
++ target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
++ target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
++ target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
++#ifdef VDSUSP
++ target->c_cc[TARGET_VDSUSP] = host->c_cc[VDSUSP];
++#endif
++ target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
++ target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
++#ifdef VLNEXT
++ target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
++#endif
++#ifdef VDISCARD
++ target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
++#endif
++ target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
++ target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
++#ifdef VSTATUS
++ target->c_cc[TARGET_VSTATUS] = host->c_cc[VSTATUS];
++#endif
++
++ target->c_ispeed = tswap32(host->c_ispeed);
++ target->c_ospeed = tswap32(host->c_ospeed);
++}
++
++static const StructEntry struct_termios_def = {
++ .convert = { host_to_target_termios, target_to_host_termios },
++ .size = { sizeof(struct target_termios), sizeof(struct termios) },
++ .align = { __alignof__(struct target_termios),
++ __alignof__(struct termios) },
++};
++
++/* kernel structure types definitions */
++
++#define STRUCT(name, ...) STRUCT_ ## name,
++#define STRUCT_SPECIAL(name) STRUCT_ ## name,
++enum {
++#ifdef __FreeBSD__
++#include "freebsd/syscall_types.h"
++#else
++#warning No syscall_types.h
++#endif
++};
++#undef STRUCT
++#undef STRUCT_SPECIAL
++
++#define STRUCT(name, ...) \
++ static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
++#define STRUCT_SPECIAL(name)
++#ifdef __FreeBSD__
++#include "freebsd/syscall_types.h"
++#else
++#warning No syscall_types.h
++#endif
++#undef STRUCT
++#undef STRUCT_SPECIAL
++
++typedef struct IOCTLEntry IOCTLEntry;
++
++typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
++ int fd, abi_long cmd, abi_long arg);
++
++struct IOCTLEntry {
++ unsigned int target_cmd;
++ unsigned int host_cmd;
++ const char *name;
++ int access;
++ do_ioctl_fn *do_ioctl;
++ const argtype arg_type[5];
++};
++
++#define MAX_STRUCT_SIZE 4096
++
++static IOCTLEntry ioctl_entries[] = {
++#define IOC_ 0x0000
++#define IOC_R 0x0001
++#define IOC_W 0x0002
++#define IOC_RW (IOC_R | IOC_W)
++#define IOCTL(cmd, access, ...) \
++ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
++#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
++ { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
++#ifdef __FreeBSD__
++#include "freebsd/ioctl.h"
++#else
++#warning No ioctl.h
++#endif
++ { 0, 0 },
++};
++
++static abi_long
++do_ioctl(int fd, abi_long cmd, abi_long arg)
++{
++ const IOCTLEntry *ie;
++ const argtype *arg_type;
++ abi_long ret;
++ uint8_t buf_temp[MAX_STRUCT_SIZE];
++ int target_size;
++ void *argptr;
++
++ ie = ioctl_entries;
++ for(;;) {
++ if (0 == ie->target_cmd) {
++ gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
++ return (-TARGET_ENOSYS);
++ }
++ if (ie->target_cmd == cmd)
++ break;
++ ie++;
++ }
++ arg_type = ie->arg_type;
++#if defined(DEBUG)
++ gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
++#endif
++ if (ie->do_ioctl) {
++ return (ie->do_ioctl(ie, buf_temp, fd, cmd, arg));
++ }
++
++ switch(arg_type[0]) {
++ case TYPE_NULL:
++ /* no argument */
++ ret = get_errno(ioctl(fd, ie->host_cmd));
++ break;
++
++ case TYPE_PTRVOID:
++ case TYPE_INT:
++ /* int argument */
++ ret = get_errno(ioctl(fd, ie->host_cmd, arg));
++ break;
++
++ case TYPE_PTR:
++ arg_type++;
++ target_size = thunk_type_size(arg_type, 0);
++ switch(ie->access) {
++ case IOC_R:
++ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
++ if (!is_error(ret)) {
++ argptr = lock_user(VERIFY_WRITE, arg,
++ target_size, 0);
++ if (!argptr)
++ return (-TARGET_EFAULT);
++ thunk_convert(argptr, buf_temp, arg_type,
++ THUNK_TARGET);
++ unlock_user(argptr, arg, target_size);
++ }
++ break;
++
++ case IOC_W:
++ argptr = lock_user(VERIFY_READ, arg, target_size, 1);
++ if (!argptr)
++ return (-TARGET_EFAULT);
++ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
++ unlock_user(argptr, arg, 0);
++ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
++
++ case IOC_RW:
++ default:
++ argptr = lock_user(VERIFY_READ, arg, target_size, 1);
++ if (!argptr)
++ return (-TARGET_EFAULT);
++ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
++ unlock_user(argptr, arg, 0);
++ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
++ if (!is_error(ret)) {
++ argptr = lock_user(VERIFY_WRITE, arg,
++ target_size, 0);
++ if (!argptr)
++ return (-TARGET_EFAULT);
++ thunk_convert(argptr, buf_temp, arg_type,
++ THUNK_TARGET);
++ unlock_user(argptr, arg, target_size);
++ }
++ break;
++ }
++ break;
++
++ default:
++ gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
++ (long)cmd, arg_type[0]);
++ ret = -TARGET_ENOSYS;
++ break;
++ }
++ return (ret);
++}
++
++/* 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>. */
++abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
++ abi_long arg2, abi_long arg3, abi_long arg4,
++ abi_long arg5, abi_long arg6, abi_long arg7,
++ abi_long arg8)
++{
++ abi_long ret;
++ void *p;
++
++#ifdef DEBUG
++ gemu_log("freebsd syscall %d\n", num);
++#endif
++ if(do_strace)
++ print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
++
++ switch(num) {
++ case TARGET_FREEBSD_NR_exit:
++#ifdef TARGET_GPROF
++ _mcleanup();
++#endif
++ gdb_exit(cpu_env, arg1);
++ /* XXX: should free thread stack and CPU env */
++ _exit(arg1);
++ ret = 0; /* avoid warning */
++ break;
++ case TARGET_FREEBSD_NR_read:
++ if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
++ goto efault;
++ ret = get_errno(read(arg1, p, arg3));
++ unlock_user(p, arg2, ret);
++ break;
++
++ case TARGET_FREEBSD_NR_readv:
++ {
++ int count = arg3;
++ struct iovec *vec;
++
++ vec = alloca(count * sizeof(struct iovec));
++ if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
++ goto efault;
++ ret = get_errno(readv(arg1, vec, count));
++ unlock_iovec(vec, arg2, count, 1);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_pread:
++ if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
++ goto efault;
++ ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
++ unlock_user(p, arg2, ret);
++ break;
++
++ case TARGET_FREEBSD_NR_preadv:
++ {
++ int count = arg3;
++ struct iovec *vec;
++
++ vec = alloca(count * sizeof(struct iovec));
++ if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
++ goto efault;
++ ret = get_errno(preadv(arg1, vec, count,
++ target_offset64(arg4, arg5)));
++ unlock_iovec(vec, arg2, count, 1);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_write:
++ if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
++ goto efault;
++ ret = get_errno(write(arg1, p, arg3));
++ unlock_user(p, arg2, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_writev:
++ {
++ int count = arg3;
++ struct iovec *vec;
++
++ vec = alloca(count * sizeof(struct iovec));
++ if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
++ goto efault;
++ ret = get_errno(writev(arg1, vec, count));
++ unlock_iovec(vec, arg2, count, 0);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_pwrite:
++ if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
++ goto efault;
++ ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
++ unlock_user(p, arg2, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_pwritev:
++ {
++ int count = arg3;
++ struct iovec *vec;
++
++ vec = alloca(count * sizeof(struct iovec));
++ if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
++ goto efault;
++ ret = get_errno(pwritev(arg1, vec, count,
++ target_offset64(arg4, arg5)));
++ unlock_iovec(vec, arg2, count, 0);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_open:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(open(path(p),
++ target_to_host_bitmask(arg2, fcntl_flags_tbl),
++ arg3));
++ unlock_user(p, arg1, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_openat:
++ if (!(p = lock_user_string(arg2)))
++ goto efault;
++ ret = get_errno(openat(arg1, path(p),
++ target_to_host_bitmask(arg3, fcntl_flags_tbl),
++ arg4));
++ unlock_user(p, arg2, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_close:
++ ret = get_errno(close(arg1));
++ break;
++
++ case TARGET_FREEBSD_NR_closefrom:
++ ret = 0;
++ closefrom(arg1);
++ break;
++
++ case TARGET_FREEBSD_NR_revoke:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(revoke(p));
++ unlock_user(p, arg1, 0);
++ break;
++
++#ifdef TARGET_FREEBSD_NR_creat
++ case TARGET_FREEBSD_NR_creat:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(creat(p, arg2));
++ unlock_user(p, arg1, 0);
++ break;
++#endif
++
++ case TARGET_FREEBSD_NR_mmap:
++ ret = get_errno(target_mmap(arg1, arg2, arg3,
++ target_to_host_bitmask(arg4, mmap_flags_tbl),
++ arg5,
++ arg6));
++ break;
++
++ case TARGET_FREEBSD_NR_munmap:
++ ret = get_errno(target_munmap(arg1, arg2));
++ break;
++
++ case TARGET_FREEBSD_NR_mprotect:
++ ret = get_errno(target_mprotect(arg1, arg2, arg3));
++ break;
++
++ case TARGET_FREEBSD_NR_msync:
++ ret = get_errno(msync(g2h(arg1), arg2, arg3));
++ break;
++
++ case TARGET_FREEBSD_NR_mlock:
++ ret = get_errno(mlock(g2h(arg1), arg2));
++ break;
++
++ case TARGET_FREEBSD_NR_munlock:
++ ret = get_errno(munlock(g2h(arg1), arg2));
++ break;
++
++ case TARGET_FREEBSD_NR_mlockall:
++ ret = get_errno(mlockall(arg1));
++ break;
++
++ case TARGET_FREEBSD_NR_munlockall:
++ ret = get_errno(munlockall());
++ break;
++
++ case TARGET_FREEBSD_NR_madvise:
++ /*
++ * A straight passthrough may not be safe because qemu sometimes
++ * turns private file-backed mapping into anonymous mappings. This
++ * will break MADV_DONTNEED. This is a hint, so ignoring and returing
++ * success is ok.
++ */
++ ret = get_errno(0);
++ break;
++
++ case TARGET_FREEBSD_NR_break:
+ ret = do_obreak(arg1);
+ break;
+ #ifdef __FreeBSD__
+@@ -2727,18 +4206,30 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+ break;
+
+ case TARGET_FREEBSD_NR_stat:
+- if (!(p = lock_user_string(arg1)))
+- goto efault;
+- ret = get_errno(stat(path(p), &st));
+- unlock_user(p, arg1, 0);
+- goto do_stat;
++ {
++ struct stat st;
++
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(stat(path(p), &st));
++ unlock_user(p, arg1, 0);
++ if (0 == ret)
++ ret = host_to_target_stat(arg2, &st);
++ }
++ break;
+
+ case TARGET_FREEBSD_NR_lstat:
+- if (!(p = lock_user_string(arg1)))
+- goto efault;
+- ret = get_errno(lstat(path(p), &st));
+- unlock_user(p, arg1, 0);
+- goto do_stat;
++ {
++ struct stat st;
++
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(lstat(path(p), &st));
++ unlock_user(p, arg1, 0);
++ if (0 == ret)
++ ret = host_to_target_stat(arg2, &st);
++ }
++ break;
+
+ case TARGET_FREEBSD_NR_nstat:
+ case TARGET_FREEBSD_NR_nfstat:
+@@ -2747,42 +4238,11 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
+ break;
+
+ case TARGET_FREEBSD_NR_fstat:
+- {
+- ret = get_errno(fstat(arg1, &st));
+-
+-do_stat:
+- if (!is_error(ret)) {
+- struct target_freebsd_stat *target_st;
+-
+- if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
+- goto efault;
+- memset(target_st, 0, sizeof(*target_st));
+- __put_user(st.st_dev, &target_st->st_dev);
+- __put_user(st.st_ino, &target_st->st_ino);
+- __put_user(st.st_mode, &target_st->st_mode);
+- __put_user(st.st_nlink, &target_st->st_nlink);
+- __put_user(st.st_uid, &target_st->st_uid);
+- __put_user(st.st_gid, &target_st->st_gid);
+- __put_user(st.st_rdev, &target_st->st_rdev);
+- __put_user(st.st_atim.tv_sec, &target_st->st_atim.tv_sec);
+- __put_user(st.st_atim.tv_nsec, &target_st->st_atim.tv_nsec);
+- __put_user(st.st_mtim.tv_sec, &target_st->st_mtim.tv_sec);
+- __put_user(st.st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec);
+- __put_user(st.st_ctim.tv_sec, &target_st->st_ctim.tv_sec);
+- __put_user(st.st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec);
+- __put_user(st.st_size, &target_st->st_size);
+- __put_user(st.st_blocks, &target_st->st_blocks);
+- __put_user(st.st_blksize, &target_st->st_blksize);
+- __put_user(st.st_flags, &target_st->st_flags);
+- __put_user(st.st_gen, &target_st->st_gen);
+- /* st_lspare not used */
+- __put_user(st.st_birthtim.tv_sec,
+- &target_st->st_birthtim.tv_sec);
+- __put_user(st.st_birthtim.tv_nsec,
+- &target_st->st_birthtim.tv_nsec);
+- unlock_user_struct(target_st, arg2, 1);
+- }
+-
++ {
++ struct stat st;
++ ret = get_errno(fstat(arg1, &st));
++ if (! ret)
++ ret = host_to_target_stat(arg2, &st);
+ }
+ break;
+
+@@ -2845,7 +4305,7 @@ do_stat:
+ }
+ ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL));
+ if (!is_error(ret)) {
+- if (fbsd_copy_to_user_timeval(&tv, arg1))
++ if (host_to_target_timeval(&tv, arg1))
+ goto efault;
+ }
+ }
+@@ -2864,7 +4324,7 @@ do_stat:
+ __get_user(tz.tz_dsttime, &target_tz->tz_dsttime);
+ unlock_user_struct(target_tz, arg2, 1);
+ }
+- if (copy_from_user_timeval(&tv, arg1))
++ if (target_to_host_timeval(&tv, arg1))
+ goto efault;
+ ret = get_errno(settimeofday(&tv, arg2 != 0 ? & tz : NULL));
+ }
+@@ -3155,8 +4615,8 @@ do_stat:
+
+ if (arg2) {
+ pvalue = &value;
+- if (copy_from_user_timeval(&pvalue->it_interval,
+- arg2) || copy_from_user_timeval(
++ if (target_to_host_timeval(&pvalue->it_interval,
++ arg2) || target_to_host_timeval(
+ &pvalue->it_value, arg2 +
+ sizeof(struct target_timeval)))
+ goto efault;
+@@ -3165,8 +4625,8 @@ do_stat:
+ }
+ ret = get_errno(setitimer(arg1, pvalue, &ovalue));
+ if (!is_error(ret) && arg3) {
+- if (fbsd_copy_to_user_timeval(&ovalue.it_interval, arg3)
+- || fbsd_copy_to_user_timeval(&ovalue.it_value,
++ if (host_to_target_timeval(&ovalue.it_interval, arg3)
++ || host_to_target_timeval(&ovalue.it_value,
+ arg3 + sizeof(struct target_timeval)))
+ goto efault;
+ }
+@@ -3179,8 +4639,8 @@ do_stat:
+
+ ret = get_errno(getitimer(arg1, &value));
+ if (!is_error(ret) && arg2) {
+- if (fbsd_copy_to_user_timeval(&value.it_interval, arg2)
+- || fbsd_copy_to_user_timeval(&value.it_value,
++ if (host_to_target_timeval(&value.it_interval, arg2)
++ || host_to_target_timeval(&value.it_value,
+ arg2 + sizeof(struct target_timeval)))
+ goto efault;
+ }
+@@ -3192,8 +4652,8 @@ do_stat:
+ struct timeval *tvp, tv[2];
+
+ if (arg2) {
+- if (copy_from_user_timeval(&tv[0], arg2)
+- || copy_from_user_timeval(&tv[1],
++ if (target_to_host_timeval(&tv[0], arg2)
++ || target_to_host_timeval(&tv[1],
+ arg2 + sizeof(struct target_timeval)))
+
+ goto efault;
+@@ -3213,8 +4673,8 @@ do_stat:
+ struct timeval *tvp, tv[2];
+
+ if (arg2) {
+- if (copy_from_user_timeval(&tv[0], arg2)
+- || copy_from_user_timeval(&tv[1],
++ if (target_to_host_timeval(&tv[0], arg2)
++ || target_to_host_timeval(&tv[1],
+ arg2 + sizeof(struct target_timeval)))
+
+ goto efault;
+@@ -3234,8 +4694,8 @@ do_stat:
+ struct timeval *tvp, tv[2];
+
+ if (arg2) {
+- if (copy_from_user_timeval(&tv[0], arg2)
+- || copy_from_user_timeval(&tv[1],
++ if (target_to_host_timeval(&tv[0], arg2)
++ || target_to_host_timeval(&tv[1],
+ arg2 + sizeof(struct target_timeval)))
+ goto efault;
+ tvp = tv;
+@@ -3251,8 +4711,8 @@ do_stat:
+ struct timeval *tvp, tv[2];
+
+ if (arg3) {
+- if (copy_from_user_timeval(&tv[0], arg3)
+- || copy_from_user_timeval(&tv[1],
++ if (target_to_host_timeval(&tv[0], arg3)
++ || target_to_host_timeval(&tv[1],
+ arg3 + sizeof(struct target_timeval)))
+ goto efault;
+ tvp = tv;
+@@ -4024,6 +5484,10 @@ do_stat:
+ ret = do_socketpair(arg1, arg2, arg3, arg4);
+ break;
+
++ case TARGET_FREEBSD_NR_shutdown:
++ ret = get_errno(shutdown(arg1, arg2));
++ break;
++
+ case TARGET_FREEBSD_NR_getpriority:
+ /*
+ * Note that negative values are valid for getpriority, so we must
+@@ -4165,8 +5629,31 @@ do_stat:
+ break;
+
+ case TARGET_FREEBSD_NR_getresuid:
++ {
++ uid_t ruid, euid, suid;
++
++ ret = get_errno(getresuid(&ruid, &euid, &suid));
++ if (put_user_s32(ruid, arg1))
++ goto efault;
++ if (put_user_s32(euid, arg2))
++ goto efault;
++ if (put_user_s32(suid, arg3))
++ goto efault;
++ }
++ break;
++
+ case TARGET_FREEBSD_NR_getresgid:
+- ret = unimplemented(num);
++ {
++ gid_t rgid, egid, sgid;
++
++ ret = get_errno(getresgid(&rgid, &egid, &sgid));
++ if (put_user_s32(rgid, arg1))
++ goto efault;
++ if (put_user_s32(egid, arg2))
++ goto efault;
++ if (put_user_s32(sgid, arg3))
++ goto efault;
++ }
+ break;
+
+ case TARGET_FREEBSD_NR_setsid:
+@@ -4679,7 +6166,7 @@ do_stat:
+ long tid;
+
+ thr_self(&tid);
+- ret = do_umtx_lock(arg1, tswap32(tid));
++ ret = do_lock_umtx(arg1, tid, NULL);
+ }
+ break;
+
+@@ -4688,72 +6175,238 @@ do_stat:
+ long tid;
+
+ thr_self(&tid);
+- ret = do_umtx_unlock(arg1, tswap32(tid));
++ ret = do_unlock_umtx(arg1, tid);
+ }
+ break;
+
+ case TARGET_FREEBSD_NR__umtx_op:
+ {
+ struct timespec ts;
+- void *object = NULL;
+- int operation;
+- void *addr = NULL;
+- void *addr2 = NULL;
+-
++ long tid;
+
+ /* int _umtx_op(void *obj, int op, u_long val,
+- * void *uaddr, void *uaddr2); */
++ * void *uaddr, void *target_ts); */
+
+ abi_ulong obj = arg1;
+ int op = (int)arg2;
+ u_long val = arg3;
+- /* abi_ulong uaddr = arg4; */
+- abi_ulong uaddr2 = arg5;
++ abi_ulong uaddr = arg4;
++ abi_ulong target_ts = arg5;
+
+ switch(op) {
+ case TARGET_UMTX_OP_LOCK:
+- ret = do_umtx_lock(obj, tswap32((uint32_t)val));
++ thr_self(&tid);
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = do_lock_umtx(obj, tid, &ts);
++ } else
++ ret = do_lock_umtx(obj, tid, NULL);
+ break;
+
+ case TARGET_UMTX_OP_UNLOCK:
+- ret = do_umtx_unlock(obj, tswap32((uint32_t)val));
++ thr_self(&tid);
++ ret = do_unlock_umtx(obj, tid);
+ break;
+
+ case TARGET_UMTX_OP_WAIT:
+- if (uaddr2) {
+- if (target_to_host_timespec(&ts, uaddr2))
++ /* args: obj *, val, ts * */
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
+ goto efault;
+- addr2 = (void *)&ts;
+- }
+- ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT,
+- tswap32(val), addr, addr2));
+- break;
++ ret = do_umtx_op_wait(obj, tswapal(val), &ts);
++ } else
++ ret = do_umtx_op_wait(obj, tswapal(val), NULL);
++ 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));
++ /* args: obj *, nr_wakeup */
++ ret = do_umtx_op_wake(obj, val);
+ break;
+
+- case TARGET_UMTX_OP_MUTEX_TRYLOCK:
+ case TARGET_UMTX_OP_MUTEX_LOCK:
++ thr_self(&tid);
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = do_lock_umutex(obj, tid, &ts, 0);
++ } else {
++ ret = do_lock_umutex(obj, tid, NULL, 0);
++ }
++ break;
++
+ case TARGET_UMTX_OP_MUTEX_UNLOCK:
++ thr_self(&tid);
++ ret = do_unlock_umutex(obj, tid);
++ break;
++
++ case TARGET_UMTX_OP_MUTEX_TRYLOCK:
++ thr_self(&tid);
++ ret = do_lock_umutex(obj, tid, NULL, TARGET_UMUTEX_TRY);
++ break;
++
++ case TARGET_UMTX_OP_MUTEX_WAIT:
++ thr_self(&tid);
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = do_lock_umutex(obj, tid, &ts,
++ TARGET_UMUTEX_WAIT);
++ } else {
++ ret = do_lock_umutex(obj, tid, NULL,
++ TARGET_UMUTEX_WAIT);
++ }
++ break;
++
++ case TARGET_UMTX_OP_MUTEX_WAKE:
++ /* Don't need to do access_ok(). */
++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_MUTEX_WAKE,
++ val, NULL, NULL));
++ break;
++
+ case TARGET_UMTX_OP_SET_CEILING:
++ ret = 0; /* XXX quietly ignore these things for now */
++ break;
++
+ case TARGET_UMTX_OP_CV_WAIT:
++ /*
++ * Initialization of the struct conv is done by
++ * bzero'ing everything in userland.
++ */
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = do_cv_wait(obj, uaddr, &ts, val);
++ } else {
++ ret = do_cv_wait(obj, uaddr, NULL, val);
++ }
++ break;
++
+ case TARGET_UMTX_OP_CV_SIGNAL:
++ /*
++ * XXX
++ * User code may check if c_has_waiters is zero. Other
++ * than that it is assume that user code doesn't do
++ * much with the struct conv fields and is pretty
++ * much opauque to userland.
++ */
++ ret = do_cv_signal(obj);
++ break;
++
+ case TARGET_UMTX_OP_CV_BROADCAST:
++ /*
++ * XXX
++ * User code may check if c_has_waiters is zero. Other
++ * than that it is assume that user code doesn't do
++ * much with the struct conv fields and is pretty
++ * much opauque to userland.
++ */
++ ret = do_cv_broadcast(obj);
++ break;
++
+ case TARGET_UMTX_OP_WAIT_UINT:
++ if (! access_ok(VERIFY_READ, obj, sizeof(abi_ulong)))
++ goto efault;
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_WAIT_UINT,
++ tswap32((uint32_t)val), NULL, &ts));
++ } else
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_WAIT_UINT,
++ tswap32((uint32_t)val), NULL, NULL));
++
++ break;
++
++ case TARGET_UMTX_OP_WAIT_UINT_PRIVATE:
++ if (! access_ok(VERIFY_READ, obj, sizeof(abi_ulong)))
++ goto efault;
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_WAIT_UINT_PRIVATE,
++ tswap32((uint32_t)val), NULL, &ts));
++ } else
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_WAIT_UINT_PRIVATE,
++ tswap32((uint32_t)val), NULL, NULL));
++
++ break;
++
++ case TARGET_UMTX_OP_WAKE_PRIVATE:
++ /* Don't need to do access_ok(). */
++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_WAKE_PRIVATE,
++ val, NULL, NULL));
++ break;
++
++ case TARGET_UMTX_OP_NWAKE_PRIVATE:
++ if (! access_ok(VERIFY_READ, obj,
++ val * sizeof(uint32_t)))
++ goto efault;
++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_NWAKE_PRIVATE,
++ val, NULL, NULL));
++ break;
++
++
+ case TARGET_UMTX_OP_RW_RDLOCK:
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = do_rw_rdlock(obj, val, &ts);
++ } else
++ ret = do_rw_rdlock(obj, val, NULL);
++ break;
++
+ case TARGET_UMTX_OP_RW_WRLOCK:
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = do_rw_wrlock(obj, val, &ts);
++ } else
++ ret = do_rw_wrlock(obj, val, NULL);
++ break;
++
+ 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:
++ ret = do_rw_unlock(obj);
++ break;
++
++#ifdef UMTX_OP_MUTEX_WAKE2
++ case TARGET_UMTX_OP_MUTEX_WAKE2:
++ if (! access_ok(VERIFY_WRITE, obj,
++ sizeof(struct target_ucond))) {
++ goto efault;
++ }
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_MUTEX_WAKE2, val, NULL, NULL));
++ break;
++#endif
++
+ case TARGET_UMTX_OP_SEM_WAIT:
++ /* XXX Assumes struct _usem is opauque to the user */
++ if (! access_ok(VERIFY_WRITE, obj,
++ sizeof(struct target__usem))) {
++ goto efault;
++ }
++ if (target_ts) {
++ if (target_to_host_timespec(&ts, target_ts))
++ goto efault;
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_SEM_WAIT, 0, NULL, &ts));
++ } else {
++ ret = get_errno(_umtx_op(g2h(obj),
++ UMTX_OP_SEM_WAIT, 0, NULL, NULL));
++ }
++ break;
++
+ case TARGET_UMTX_OP_SEM_WAKE:
+- case TARGET_UMTX_OP_NWAKE_PRIVATE:
++ /* Don't need to do access_ok(). */
++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAKE,
++ val, NULL, NULL));
++ break;
++
+ default:
+ ret = -TARGET_EINVAL;
+ break;
+@@ -4761,21 +6414,150 @@ do_stat:
+ }
+ break;
+
++ case TARGET_FREEBSD_NR_getfh:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = do_getfh(path(p), arg2);
++ unlock_user(p, arg1, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_lgetfh:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = do_lgetfh(path(p), arg2);
++ unlock_user(p, arg1, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_fhopen:
++ ret = do_fhopen(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_fhstat:
++ ret = do_fhstat(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_fhstatfs:
++ ret = do_fhstatfs(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_getfsstat:
++ ret = do_getfsstat(arg1, arg2, arg3);
++ break;
++
++ case TARGET_FREEBSD_NR_statfs:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = do_statfs(path(p), arg2);
++ unlock_user(p, arg1, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_fstatfs:
++ ret = do_fstatfs(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_ioctl:
++ ret = do_ioctl(arg1, arg2, arg3);
++ break;
++
++ case TARGET_FREEBSD_NR_kenv:
++ {
++ char *n, *v;
++
++ if (!(n = lock_user_string(arg2)))
++ goto efault;
++ if (!(v = lock_user_string(arg3)))
++ goto efault;
++ ret = get_errno(kenv(arg1, n, v, arg4));
++ unlock_user(v, arg3, 0);
++ unlock_user(n, arg2, 0);
++ }
++ break;
++
++ case TARGET_FREEBSD_NR_swapon:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(swapon(path(p)));
++ unlock_user(p, arg1, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_swapoff:
++ if (!(p = lock_user_string(arg1)))
++ goto efault;
++ ret = get_errno(swapoff(path(p)));
++ unlock_user(p, arg1, 0);
++ break;
++
++ case TARGET_FREEBSD_NR_reboot:
++ ret = get_errno(reboot(arg1));
++ break;
++
++ case TARGET_FREEBSD_NR_uuidgen:
++ ret = do_uuidgen(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_mincore:
++ if (!(p = lock_user(VERIFY_WRITE, arg3, arg2, 0)))
++ goto efault;
++ ret = get_errno(mincore(g2h(arg1), arg2, p));
++ unlock_user(p, arg3, ret);
++ break;
++
++ case TARGET_FREEBSD_NR_adjtime:
++ ret = do_adjtime(arg1, arg2);
++ break;
++
++ case TARGET_FREEBSD_NR_ntp_adjtime:
++ ret = do_ntp_adjtime(arg1);
++ break;
++
++ case TARGET_FREEBSD_NR_ntp_gettime:
++ ret = do_ntp_gettime(arg1);
++ break;
++
++ case TARGET_FREEBSD_NR_vadvise:
++ ret = -TARGET_EINVAL; /* See sys_ovadvise() in vm_unix.c */
++ break;
++
++ case TARGET_FREEBSD_NR_sbrk:
++ ret = -TARGET_EOPNOTSUPP; /* see sys_sbrk() in vm_mmap.c */
++ break;
++
++ case TARGET_FREEBSD_NR_sstk:
++ ret = -TARGET_EOPNOTSUPP; /* see sys_sstk() in vm_mmap.c */
++ break;
++
+ case TARGET_FREEBSD_NR_yield:
++ case TARGET_FREEBSD_NR_sched_yield:
++ ret = get_errno(sched_yield());
++ break;
++
+ case TARGET_FREEBSD_NR_sched_setparam:
++ ret = do_sched_setparam(arg1, arg2);
++ break;
++
+ case TARGET_FREEBSD_NR_sched_getparam:
++ ret = do_sched_getparam(arg1, arg2);
++ break;
++
+ case TARGET_FREEBSD_NR_sched_setscheduler:
++ ret = do_sched_setscheduler(arg1, arg2, arg3);
++ break;
++
+ case TARGET_FREEBSD_NR_sched_getscheduler:
+- case TARGET_FREEBSD_NR_sched_yield:
++ ret = get_errno(sched_getscheduler(arg1));
++ break;
++
+ case TARGET_FREEBSD_NR_sched_get_priority_max:
+- case TARGET_FREEBSD_NR_sched_get_priority_min:
+- case TARGET_FREEBSD_NR_sched_rr_get_interval:
++ ret = get_errno(sched_get_priority_max(arg1));
++ break;
+
+- case TARGET_FREEBSD_NR_reboot:
+- case TARGET_FREEBSD_NR_shutdown:
++ case TARGET_FREEBSD_NR_sched_get_priority_min:
++ ret = get_errno(sched_get_priority_min(arg1));
++ break;
+
+- case TARGET_FREEBSD_NR_swapon:
+- case TARGET_FREEBSD_NR_swapoff:
++ case TARGET_FREEBSD_NR_sched_rr_get_interval:
++ ret = do_sched_rr_get_interval(arg1, arg2);
++ break;
+
+ case TARGET_FREEBSD_NR_cpuset:
+ case TARGET_FREEBSD_NR_cpuset_getid:
+@@ -4789,22 +6571,10 @@ do_stat:
+ case TARGET_FREEBSD_NR_rctl_remove_rule:
+ case TARGET_FREEBSD_NR_rctl_get_limits:
+
+- case TARGET_FREEBSD_NR_ntp_adjtime:
+- case TARGET_FREEBSD_NR_ntp_gettime:
+-
+ case TARGET_FREEBSD_NR_sctp_peeloff:
+ case TARGET_FREEBSD_NR_sctp_generic_sendmsg:
+ case TARGET_FREEBSD_NR_sctp_generic_recvmsg:
+
+- case TARGET_FREEBSD_NR_getfh:
+- case TARGET_FREEBSD_NR_lgetfh:
+- case TARGET_FREEBSD_NR_fhstatfs:
+- case TARGET_FREEBSD_NR_fhopen:
+- case TARGET_FREEBSD_NR_fhstat:
+-
+- case TARGET_FREEBSD_NR_getfsstat:
+- case TARGET_FREEBSD_NR_fstatfs:
+-
+ case TARGET_FREEBSD_NR_modfnext:
+ case TARGET_FREEBSD_NR_modfind:
+ case TARGET_FREEBSD_NR_kldload:
+@@ -4821,8 +6591,6 @@ do_stat:
+ case TARGET_FREEBSD_NR_quota:
+ #endif
+
+- case TARGET_FREEBSD_NR_adjtime:
+-
+ #ifdef TARGET_FREEBSD_NR_gethostid
+ case TARGET_FREEBSD_NR_gethostid:
+ #endif
+@@ -4833,13 +6601,6 @@ do_stat:
+ case TARGET_FREEBSD_NR_sethostname:
+ #endif
+
+- case TARGET_FREEBSD_NR_mincore:
+-
+- case TARGET_FREEBSD_NR_vadvise:
+-
+- case TARGET_FREEBSD_NR_sbrk:
+- case TARGET_FREEBSD_NR_sstk:
+-
+ #ifdef TARGET_FREEBSD_NR_getkerninfo
+ case TARGET_FREEBSD_NR_getkerninfo:
+ #endif
+@@ -4847,8 +6608,6 @@ do_stat:
+ case TARGET_FREEBSD_NR_getpagesize:
+ #endif
+
+- case TARGET_FREEBSD_NR_revoke:
+-
+ case TARGET_FREEBSD_NR_profil:
+ case TARGET_FREEBSD_NR_ktrace:
+
+@@ -4857,12 +6616,13 @@ do_stat:
+ case TARGET_FREEBSD_NR_jail_get:
+ case TARGET_FREEBSD_NR_jail_set:
+ case TARGET_FREEBSD_NR_jail_remove:
++ ret = unimplemented(num);
++ break;
+
+ case TARGET_FREEBSD_NR_cap_enter:
+ case TARGET_FREEBSD_NR_cap_getmode:
+-
+- case TARGET_FREEBSD_NR_kenv:
+- case TARGET_FREEBSD_NR_uuidgen:
++ ret = unimplemented(num);
++ break;
+
+ case TARGET_FREEBSD_NR___mac_get_proc:
+ case TARGET_FREEBSD_NR___mac_set_proc:
+@@ -4873,6 +6633,8 @@ do_stat:
+ case TARGET_FREEBSD_NR___mac_get_link:
+ case TARGET_FREEBSD_NR___mac_set_link:
+ case TARGET_FREEBSD_NR_mac_syscall:
++ ret = unimplemented(num);
++ break;
+
+ case TARGET_FREEBSD_NR_audit:
+ case TARGET_FREEBSD_NR_auditon:
+@@ -4881,6 +6643,8 @@ do_stat:
+ case TARGET_FREEBSD_NR_getaudit_addr:
+ case TARGET_FREEBSD_NR_setaudit_addr:
+ case TARGET_FREEBSD_NR_auditctl:
++ ret = unimplemented(num);
++ break;
+
+
+ #ifdef TARGET_FREEBSD_NR_obreak
+@@ -4894,7 +6658,6 @@ do_stat:
+ case TARGET_FREEBSD_NR_sendfile:
+ case TARGET_FREEBSD_NR_ptrace:
+ case TARGET_FREEBSD_NR_utrace:
+- case TARGET_FREEBSD_NR_ioctl:
+ ret = unimplemented(num);
+ break;
+
+@@ -5061,4 +6824,43 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
+
+ void syscall_init(void)
+ {
++ IOCTLEntry *ie;
++ const argtype *arg_type;
++ int size;
++
++#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
++#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
++#ifdef __FreeBSD__
++#include "freebsd/syscall_types.h"
++#else
++#warning No syscall_types.h
++#endif
++#undef STRUCT
++#undef STRUCT_SPECIAL
++
++ /*
++ * Patch the ioctl size if necessary using the fact that no
++ * ioctl has all the bits at '1' in the size field
++ * (IOCPARM_MAX - 1).
++ */
++ ie = ioctl_entries;
++ while (ie->target_cmd != 0) {
++ if (((ie->target_cmd >> TARGET_IOCPARM_SHIFT) &
++ TARGET_IOCPARM_MASK) == TARGET_IOCPARM_MASK) {
++ arg_type = ie->arg_type;
++ if (arg_type[0] != TYPE_PTR) {
++ fprintf(stderr,
++ "cannot patch size for ioctl 0x%x\n",
++ ie->target_cmd);
++ exit(1);
++ }
++ arg_type++;
++ size = thunk_type_size(arg_type, 0);
++ ie->target_cmd = (ie->target_cmd & ~(TARGET_IOCPARM_MASK
++ << TARGET_IOCPARM_SHIFT)) |
++ (size << TARGET_IOCPARM_SHIFT);
++ }
++ ie++;
++ }
++
+ }
+diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h
+index 2879d83..3eb760b 100644
+--- a/bsd-user/syscall_defs.h
++++ b/bsd-user/syscall_defs.h
+@@ -555,7 +555,7 @@ struct target_rtprio {
+ */
+
+ struct target_umtx {
+- uint32_t u_owner; /* Owner of the mutex. */
++ abi_ulong u_owner; /* Owner of the mutex. */
+ };
+
+ struct target_umutex {
+@@ -573,7 +573,7 @@ struct target_ucond {
+ };
+
+ struct target_urwlock {
+- int32_t rw_state;
++ uint32_t rw_state;
+ uint32_t rw_flags;
+ uint32_t rw_blocked_readers;
+ uint32_t rw_blocked_writers;
+@@ -613,7 +613,146 @@ struct target__usem {
+ #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
++#define TARGET_UMTX_OP_MUTEX_WAKE2 22
++#define TARGET_UMTX_OP_MAX 23
+
+ /* flags for UMTX_OP_CV_WAIT */
+-#define TARGET_CHECK_UNPARKING 0x01
++#define TARGET_CVWAIT_CHECK_UNPARKING 0x01
++#define TARGET_CVWAIT_ABSTIME 0x02
++#define TARGET_CVWAIT_CLOCKID 0x04
++
++#define TARGET_UMTX_UNOWNED 0x0
++#define TARGET_UMUTEX_UNOWNED 0x0
++#define TARGET_UMTX_CONTESTED (abi_long)(0x8000000000000000)
++#define TARGET_UMUTEX_CONTESTED 0x80000000U
++
++/* flags for umutex */
++#define TARGET_UMUTEX_ERROR_CHECK 0x0002 /* Error-checking mutex */
++#define TARGET_UMUTEX_PRIO_INHERIT 0x0004 /* Priority inherited mutex */
++#define TARGET_UMUTEX_PRIO_PROTECT 0x0008 /* Priority protect mutex */
++
++#define TARGET_UMUTEX_TRY 1
++#define TARGET_UMUTEX_WAIT 2
++
++/* urwlock flags */
++#define TARGET_URWLOCK_PREFER_READER 0x0002
++#define TARGET_URWLOCK_WRITE_OWNER 0x80000000U
++#define TARGET_URWLOCK_WRITE_WAITERS 0x40000000U
++#define TARGET_URWLOCK_READ_WAITERS 0x20000000U
++#define TARGET_URWLOCK_MAX_READERS 0x1fffffffU
++#define TARGET_URWLOCK_READER_COUNT(c) ((c) & TARGET_URWLOCK_MAX_READERS)
++
++/* mount.h statfs */
++/*
++ * filesystem id type
++ */
++typedef struct target_fsid { int32_t val[2]; } target_fsid_t;
++
++/*
++ * filesystem statistics
++ */
++#define TARGET_MFSNAMELEN 16 /* length of type name include null */
++#define TARGET_MNAMELEN 88 /* size of on/from name bufs */
++#define TARGET_STATFS_VERSION 0x20030518 /* current version number */
++struct target_statfs {
++ uint32_t f_version; /* structure version number */
++ uint32_t f_type; /* type of filesystem */
++ uint64_t f_flags; /* copy of mount exported flags */
++ uint64_t f_bsize; /* filesystem fragment size */
++ uint64_t f_iosize; /* optimal transfer block size */
++ uint64_t f_blocks; /* total data blocks in filesystem */
++ uint64_t f_bfree; /* free blocks in filesystem */
++ int64_t f_bavail; /* free blocks avail to non-superuser */
++ uint64_t f_files; /* total file nodes in filesystem */
++ int64_t f_ffree; /* free nodes avail to non-superuser */
++ uint64_t f_syncwrites; /* count of sync writes since mount */
++ uint64_t f_asyncwrites; /* count of async writes since mount */
++ uint64_t f_syncreads; /* count of sync reads since mount */
++ uint64_t f_asyncreads; /* count of async reads since mount */
++ uint64_t f_spare[10]; /* unused spare */
++ uint32_t f_namemax; /* maximum filename length */
++ uid_t f_owner; /* user that mounted the filesystem */
++ target_fsid_t f_fsid; /* filesystem id */
++ char f_charspare[80]; /* spare string space */
++ char f_fstypename[TARGET_MFSNAMELEN]; /* filesys type name */
++ char f_mntfromname[TARGET_MNAMELEN]; /* mount filesystem */
++ char f_mntonname[TARGET_MNAMELEN]; /* dir on which mounted*/
++};
++
++/*
++ * File identifier.
++ * These are unique per filesystem on a single machine.
++ */
++#define TARGET_MAXFIDSZ 16
++
++struct target_fid {
++ u_short fid_len; /* len of data in bytes */
++ u_short fid_data0; /* force longword align */
++ char fid_data[TARGET_MAXFIDSZ]; /* data (variable len) */
++};
++
++/*
++ * Generic file handle
++ */
++struct target_fhandle {
++ target_fsid_t fh_fsid; /* Filesystem id of mount point */
++ struct target_fid fh_fid; /* Filesys specific id */
++};
++typedef struct target_fhandle target_fhandle_t;
++
++
++/*
++ * uuidgen. From sys/uuid.h.
++ */
++
++#define TARGET_UUID_NODE_LEN 6
++
++struct target_uuid {
++ uint32_t time_low;
++ uint16_t time_mid;
++ uint16_t time_hi_and_version;
++ uint8_t clock_seq_hi_and_reserved;
++ uint8_t clock_seq_low;
++ uint8_t node[TARGET_UUID_NODE_LEN];
++};
++
++/*
++ * ntp. From sys/timex.h.
++ */
++
++struct target_ntptimeval {
++ struct target_freebsd_timespec time;
++ abi_long maxerror;
++ abi_long esterror;
++ abi_long tai;
++ int32_t time_state;
++};
++
++struct target_timex {
++ uint32_t modes;
++ abi_long offset;
++ abi_long freq;
++ abi_long maxerror;
++ abi_long esterror;
++ int32_t status;
++ abi_long constant;
++ abi_long precision;
++ abi_long tolerance;
++
++ abi_long ppsfreq;
++ abi_long jitter;
++ int32_t shift;
++ abi_long stabil;
++ abi_long jitcnt;
++ abi_long calcnt;
++ abi_long errcnt;
++ abi_long stbcnt;
++};
++
++/*
++ * sched.h From sched.h
++ */
++
++struct target_sched_param {
++ int32_t sched_priority;
++};