diff options
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-002e | 3316 |
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; ++}; |
