mirror of
https://git.freebsd.org/ports.git
synced 2025-05-18 01:53:13 -04:00
- Update emulators/qemu-devel to 1.4.0 with preliminary bsd-user patches. Thanx to: sson, cognet, and others for much improved bsd-user support - it now runs at least quite a few mips64 and single-threaded arm binaries, see: https://wiki.freebsd.org/QemuUserModeHowTo
3316 lines
98 KiB
Text
3316 lines
98 KiB
Text
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;
|
|
+};
|