Index: Makefile =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/Makefile,v retrieving revision 1.148 diff -u -p -r1.148 Makefile --- Makefile 5 Feb 2013 16:54:21 -0000 1.148 +++ Makefile 19 Mar 2013 19:26:57 -0000 @@ -2,8 +2,7 @@ # $FreeBSD: ports/emulators/qemu-devel/Makefile,v 1.148 2013/02/05 16:54:21 svnexp Exp $ PORTNAME= qemu -PORTVERSION= 1.1.1 -PORTREVISION= 2 +PORTVERSION= 1.4.0 CATEGORIES= emulators MASTER_SITES= http://wiki.qemu.org/download/:release \ LOCAL/nox:snapshot @@ -14,8 +13,10 @@ DIST_SUBDIR= qemu/${PORTVERSION} MAINTAINER= nox@FreeBSD.org COMMENT= QEMU CPU Emulator - development version +LIB_DEPENDS= pixman-1:${PORTSDIR}/x11/pixman + HAS_CONFIGURE= yes -EXTRACT_SUFX= .tar.bz2 +USE_BZIP2= yes USE_GMAKE= yes USE_PERL5_BUILD= yes USE_PYTHON_BUILD= yes @@ -29,7 +30,8 @@ CONFLICTS_INSTALL= qemu-[0-9]* MAKE_JOBS_SAFE= yes OPTIONS_DEFINE= SAMBA SDL OPENGL GNUTLS SASL JPEG PNG CURL CDROM_DMA PCAP \ - USBREDIR GNS3 ADD_AUDIO CLANG_HACK X86_TARGETS BSD_USER + USBREDIR GNS3 ADD_AUDIO CLANG_HACK X86_TARGETS BSD_USER \ + STATIC_LINK SAMBA_DESC= samba dependency (for -smb) GNUTLS_DESC= gnutls dependency (vnc encryption) SASL_DESC= cyrus-sasl dependency (vnc encryption) @@ -40,11 +42,12 @@ CDROM_DMA_DESC= IDE CDROM DMA PCAP_DESC= pcap dependency (networking with bpf) SEABIOS_GIT_DESC= add seabios snapshot (-bios bios.bin-1.6.3.1) USBREDIR_DESC= usb device network redirection (experimental!) -GNS3_DESC= gns3 patches (udp, promiscuous multicast) +GNS3_DESC= gns3 patches (promiscuous multicast) ADD_AUDIO_DESC= Emulate more audio hardware (experimental!) CLANG_HACK_DESC= clang workaround (result slow and less stable!) X86_TARGETS_DESC= Don't build non-x86 system targets BSD_USER_DESC= Also build bsd-user targets (for testing) +STATIC_LINK_DESC= Statically link the executables OPTIONS_DEFAULT=SDL OPENGL GNUTLS SASL JPEG PNG CURL CDROM_DMA PCAP .include @@ -64,13 +67,15 @@ USE_GCC= any .if ${PORT_OPTIONS:MX86_TARGETS} .if ${PORT_OPTIONS:MBSD_USER} -CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,x86_64-bsd-user,sparc-bsd-user,sparc64-bsd-user,arm-bsd-user +CONFIGURE_ARGS+= --enable-nptl --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,x86_64-bsd-user,sparc-bsd-user,sparc64-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user,mips64-bsd-user .else CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu .endif .else .if empty(PORT_OPTIONS:MBSD_USER) CONFIGURE_ARGS+= --disable-bsd-user +.else +CONFIGURE_ARGS+= --enable-nptl .endif .endif @@ -90,13 +95,7 @@ PLIST_SUB+= NONX86="" .endif .if ${PORT_OPTIONS:MGNS3} -EXTRA_PATCHES+= ${FILESDIR}/hw_e1000_c.patch \ - ${FILESDIR}/net_c.patch \ - ${FILESDIR}/net_h.patch \ - ${FILESDIR}/net_udp_c.patch \ - ${FILESDIR}/net_udp_h.patch \ - ${FILESDIR}/Makefile_objs.patch \ - ${FILESDIR}/gns3-qemu-options.hx.patch +EXTRA_PATCHES+= ${FILESDIR}/hw_e1000_c.patch .endif WITHOUT_CPU_CFLAGS=yes #to avoid problems with register allocation @@ -105,6 +104,8 @@ CONFIGURE_ARGS+= --prefix=${PREFIX} --cc --disable-linux-user --disable-linux-aio \ --disable-kvm --disable-xen \ --smbd=${LOCALBASE}/sbin/smbd \ + --enable-debug \ + --enable-debug-info \ --extra-cflags=-I${WRKSRC}\ -I${LOCALBASE}/include\ -DPREFIX=\\\"${PREFIX}\\\" .if empty(PORT_OPTIONS:MSDL) @@ -160,6 +161,10 @@ RUN_DEPENDS+= usbredir>=0.4.3:${PORTSDIR CONFIGURE_ARGS+= --enable-pcap .endif +.if ${PORT_OPTIONS:MSTATIC_LINK} +CONFIGURE_ARGS+= --static +.endif + .if ${PORT_OPTIONS:MADD_AUDIO} CONFIGURE_ARGS+= --audio-card-list=ac97,es1370,sb16,cs4231a,adlib,gus,hda .endif @@ -201,9 +206,11 @@ MAKE_ENV+= COMPILER_PATH=${LOCALBASE}/bi .endif post-patch: +.if ${OSVERSION} < 900000 + @${REINPLACE_CMD} -e '/LIBS/s|-lprocstat||' ${WRKSRC}/configure +.endif .if ${PORT_OPTIONS:MPCAP} @cd ${WRKSRC} && ${PATCH} --quiet < ${FILESDIR}/pcap-patch - @${REINPLACE_CMD} -f ${FILESDIR}/pcap-client-type.sed ${WRKSRC}/net.h .endif .if empty(PORT_OPTIONS:MCDROM_DMA) @cd ${WRKSRC} && ${PATCH} --quiet < ${FILESDIR}/cdrom-dma-patch Index: distinfo =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/distinfo,v retrieving revision 1.65 diff -u -p -r1.65 distinfo --- distinfo 19 Jul 2012 20:15:43 -0000 1.65 +++ distinfo 16 Feb 2013 20:17:51 -0000 @@ -1,2 +1,2 @@ -SHA256 (qemu/1.1.1/qemu-1.1.1.tar.bz2) = 004a3032b504e70174c504d6c156b1ec3445abd9913602af0d7a5ac0703ddf5c -SIZE (qemu/1.1.1/qemu-1.1.1.tar.bz2) = 11712524 +SHA256 (qemu/1.4.0/qemu-1.4.0.tar.bz2) = 066297ed77408fb7588889c271a85cf3c259ad55c939315988e6062d7708eda8 +SIZE (qemu/1.4.0/qemu-1.4.0.tar.bz2) = 10419510 Index: pkg-plist =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/pkg-plist,v retrieving revision 1.38 diff -u -p -r1.38 pkg-plist --- pkg-plist 19 Jul 2012 20:15:43 -0000 1.38 +++ pkg-plist 16 Feb 2013 22:02:28 -0000 @@ -14,6 +14,7 @@ bin/qemu-system-i386 %%NONX86%%bin/qemu-system-mips64 %%NONX86%%bin/qemu-system-mips64el %%NONX86%%bin/qemu-system-mipsel +%%NONX86%%bin/qemu-system-or32 %%NONX86%%bin/qemu-system-ppc %%NONX86%%bin/qemu-system-ppc64 %%NONX86%%bin/qemu-system-ppcemb @@ -22,8 +23,13 @@ bin/qemu-system-i386 %%NONX86%%bin/qemu-system-sh4eb %%NONX86%%bin/qemu-system-sparc %%NONX86%%bin/qemu-system-sparc64 +%%NONX86%%bin/qemu-system-unicore32 %%BSD_USER%%bin/qemu-arm +%%BSD_USER%%bin/qemu-armeb %%BSD_USER%%bin/qemu-i386 +%%BSD_USER%%bin/qemu-mips +%%BSD_USER%%bin/qemu-mips64 +%%BSD_USER%%bin/qemu-mipsel %%BSD_USER%%bin/qemu-sparc %%BSD_USER%%bin/qemu-sparc64 %%BSD_USER%%bin/qemu-x86_64 @@ -40,6 +46,8 @@ etc/qemu-ifdown.sample etc/qemu/target-x86_64.conf.sample @exec if [ ! -f %D/etc/qemu/target-x86_64.conf ] ; then cp -p %D/%F %D/etc/qemu/target-x86_64.conf; fi @dirrmtry etc/qemu +%%DATADIR%%/acpi-dsdt.aml +%%DATADIR%%/q35-acpi-dsdt.aml %%DATADIR%%/bios.bin %%DATADIR%%/vgabios.bin %%DATADIR%%/vgabios-cirrus.bin @@ -58,7 +66,6 @@ etc/qemu/target-x86_64.conf.sample %%DATADIR%%/pxe-pcnet.rom %%DATADIR%%/pxe-virtio.rom %%DATADIR%%/petalogix-ml605.dtb -%%DATADIR%%/mpc8544ds.dtb %%DATADIR%%/spapr-rtas.bin %%DATADIR%%/slof.bin %%DATADIR%%/s390-zipl.rom @@ -67,10 +74,10 @@ etc/qemu/target-x86_64.conf.sample %%DATADIR%%/sgabios.bin %%DATADIR%%/petalogix-s3adsp1800.dtb %%DATADIR%%/bamboo.dtb -%%DATADIR%%/cpus-x86_64.conf %%DATADIR%%/kvmvapic.bin %%DATADIR%%/qemu-icon.bmp %%DATADIR%%/keymaps/ar +%%DATADIR%%/keymaps/bepo %%DATADIR%%/keymaps/common %%DATADIR%%/keymaps/da %%DATADIR%%/keymaps/de Index: files/Makefile_objs.patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/Makefile_objs.patch,v retrieving revision 1.1 diff -u -p -r1.1 Makefile_objs.patch --- files/Makefile_objs.patch 17 Feb 2012 22:31:17 -0000 1.1 +++ files/Makefile_objs.patch 3 Dec 2012 22:02:54 -0000 @@ -1,10 +0,0 @@ ---- qemu-0.14.1/Makefile.objs.orig Thu Jun 23 17:44:50 2011 -+++ qemu-0.14.1/Makefile.objs Thu Jun 23 17:45:01 2011 -@@ -34,6 +34,7 @@ - net-nested-y = queue.o checksum.o util.o - net-nested-y += socket.o - net-nested-y += dump.o -+net-nested-y += udp.o - net-nested-$(CONFIG_POSIX) += tap.o - net-nested-$(CONFIG_LINUX) += tap-linux.o - net-nested-$(CONFIG_WIN32) += tap-win32.o Index: files/gns3-qemu-options.hx.patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/gns3-qemu-options.hx.patch,v retrieving revision 1.1 diff -u -p -r1.1 gns3-qemu-options.hx.patch --- files/gns3-qemu-options.hx.patch 13 Jul 2011 20:01:41 -0000 1.1 +++ files/gns3-qemu-options.hx.patch 3 Dec 2012 22:02:54 -0000 @@ -1,11 +0,0 @@ ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -1050,6 +1050,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, - " connect the user mode network stack to VLAN 'n', configure its\n" - " DHCP server and enabled optional services\n" - #endif -+ "-net udp[,vlan=n],sport=sport,dport=dport,daddr=host\n" -+ " connect the vlan 'n' to a udp host (for dynamips/pemu/GNS3)\n" - #ifdef _WIN32 - "-net tap[,vlan=n][,name=str],ifname=name\n" - " connect the host TAP network interface to VLAN 'n'\n" Index: files/net_c.patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/net_c.patch,v retrieving revision 1.1 diff -u -p -r1.1 net_c.patch --- files/net_c.patch 21 Aug 2011 15:49:39 -0000 1.1 +++ files/net_c.patch 3 Dec 2012 22:02:54 -0000 @@ -1,38 +0,0 @@ ---- qemu-0.15.0/net.c.orig -+++ qemu-0.15.0/net.c -@@ -30,6 +30,7 @@ - #include "net/dump.h" - #include "net/slirp.h" - #include "net/vde.h" -+#include "net/udp.h" - #include "net/util.h" - #include "monitor.h" - #include "qemu-common.h" -@@ -1029,6 +1030,27 @@ static const struct { - }, - }, - #endif -+ [NET_CLIENT_TYPE_UDP] = { -+ .type = "udp", -+ .init = net_init_udp, -+ .desc = { -+ NET_COMMON_PARAMS_DESC, -+ { -+ .name = "sport", -+ .type = QEMU_OPT_NUMBER, -+ .help = "source port number", -+ }, { -+ .name = "daddr", -+ .type = QEMU_OPT_STRING, -+ .help = "destination IP address", -+ }, { -+ .name = "dport", -+ .type = QEMU_OPT_NUMBER, -+ .help = "destination port number", -+ }, -+ { /* end of list */ } -+ }, -+ }, - [NET_CLIENT_TYPE_DUMP] = { - .type = "dump", - .init = net_init_dump, Index: files/net_h.patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/net_h.patch,v retrieving revision 1.1 diff -u -p -r1.1 net_h.patch --- files/net_h.patch 21 Aug 2011 15:49:39 -0000 1.1 +++ files/net_h.patch 3 Dec 2012 22:02:54 -0000 @@ -1,10 +0,0 @@ ---- qemu-0.15.0/net.h.orig -+++ qemu-0.15.0/net.h -@@ -35,6 +35,7 @@ typedef enum { - NET_CLIENT_TYPE_TAP, - NET_CLIENT_TYPE_SOCKET, - NET_CLIENT_TYPE_VDE, -+ NET_CLIENT_TYPE_UDP, - NET_CLIENT_TYPE_DUMP, - - NET_CLIENT_TYPE_MAX Index: files/net_udp_c.patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/net_udp_c.patch,v retrieving revision 1.1 diff -u -p -r1.1 net_udp_c.patch --- files/net_udp_c.patch 17 Feb 2012 22:31:17 -0000 1.1 +++ files/net_udp_c.patch 3 Dec 2012 22:02:54 -0000 @@ -1,141 +0,0 @@ ---- qemu-0.14.1/net/udp.c.orig Thu Jun 23 17:09:02 2011 -+++ qemu-0.14.1/net/udp.c Thu Jun 23 17:10:17 2011 -@@ -0,0 +1,138 @@ -+/* -+ * QEMU System Emulator -+ * -+ * Copyright (c) 2003-2008 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#include "net/udp.h" -+ -+#include "config-host.h" -+ -+#ifndef _WIN32 -+#include -+#include -+#include -+#endif -+ -+#include "net.h" -+#include "qemu-char.h" -+#include "qemu-common.h" -+#include "qemu-option.h" -+#include "qemu_socket.h" -+#include "sysemu.h" -+ -+ -+typedef struct UDPState { -+ VLANClientState nc; -+ int rfd; -+ struct sockaddr_in sender; -+} UDPState; -+ -+static void udp_to_qemu(void *opaque) -+{ -+ UDPState *s = opaque; -+ uint8_t buf[4096]; -+ int size; -+ -+ size = recvfrom(s->rfd, (char *)buf, sizeof(buf), 0, NULL, NULL); -+ if (size > 0) { -+ qemu_send_packet(&s->nc, buf, size); -+ } -+} -+ -+static ssize_t udp_receive(VLANClientState *nc, const uint8_t *buf, size_t size) -+{ -+ UDPState *s = DO_UPCAST(UDPState, nc, nc); -+ int ret; -+ -+ do { -+ ret = sendto(s->rfd, (const char *)buf, size, 0, (struct sockaddr *)&s->sender, sizeof (s->sender)); -+ } while (ret < 0 && errno == EINTR); -+ -+ return ret; -+} -+ -+static void udp_cleanup(VLANClientState *nc) -+{ -+ UDPState *s = DO_UPCAST(UDPState, nc, nc); -+ qemu_set_fd_handler(s->rfd, NULL, NULL, NULL); -+ close(s->rfd); -+} -+ -+static NetClientInfo net_udp_info = { -+ .type = NET_CLIENT_TYPE_UDP, -+ .size = sizeof(UDPState), -+ .receive = udp_receive, -+ .cleanup = udp_cleanup, -+}; -+ -+static int net_udp_init(VLANState *vlan, const char *model, -+ const char *name, int sport, -+ const char *daddr, int dport) -+{ -+ VLANClientState *nc; -+ UDPState *s; -+ struct sockaddr_in receiver; -+ int ret; -+ -+ nc = qemu_new_net_client(&net_udp_info, vlan, NULL, model, name); -+ -+ snprintf(nc->info_str, sizeof(nc->info_str),"udp: %i->%s:%i", -+ sport, daddr, dport); -+ -+ s = DO_UPCAST(UDPState, nc, nc); -+ -+ s->rfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); -+ receiver.sin_family = AF_INET; -+ receiver.sin_addr.s_addr = INADDR_ANY; -+ receiver.sin_port = htons(sport); -+ ret = bind(s->rfd, (struct sockaddr *)&receiver, sizeof(receiver)); -+ -+ if (ret == -1) { -+ fprintf (stderr, "bind error:%s\n", strerror(errno)); -+ return ret; -+ } -+ -+ memset((char*)&s->sender, 0,sizeof(s->sender)); -+ s->sender.sin_family = AF_INET; -+ s->sender.sin_port = htons(dport); -+ inet_aton(daddr, &s->sender.sin_addr); -+ -+ qemu_set_fd_handler(s->rfd, udp_to_qemu, NULL, s); -+ -+ return 0; -+} -+ -+int net_init_udp(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan) -+{ -+ const char *daddr; -+ int sport, dport; -+ -+ daddr = qemu_opt_get(opts, "daddr"); -+ -+ sport = qemu_opt_get_number(opts, "sport", 0); -+ dport = qemu_opt_get_number(opts, "dport", 0); -+ -+ if (net_udp_init(vlan, "udp", name, sport, daddr, dport) == -1) { -+ return -1; -+ } -+ -+ return 0; -+} Index: files/net_udp_h.patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/net_udp_h.patch,v retrieving revision 1.1 diff -u -p -r1.1 net_udp_h.patch --- files/net_udp_h.patch 17 Feb 2012 22:31:17 -0000 1.1 +++ files/net_udp_h.patch 3 Dec 2012 22:02:54 -0000 @@ -1,35 +0,0 @@ ---- qemu-0.14.1/net/udp.h.orig Thu Jun 23 17:12:45 2011 -+++ qemu-0.14.1/net/udp.h Thu Jun 23 17:12:28 2011 -@@ -0,0 +1,32 @@ -+/* -+ * QEMU System Emulator -+ * -+ * Copyright (c) 2003-2008 Fabrice Bellard -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+#ifndef QEMU_NET_UDP_H -+#define QEMU_NET_UDP_H -+ -+#include "qemu-common.h" -+#include "qemu-option.h" -+ -+int net_init_udp(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan); -+ -+#endif /* QEMU_NET_UDP_H */ Index: files/patch-90_security =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-90_security,v retrieving revision 1.9 diff -u -p -r1.9 patch-90_security --- files/patch-90_security 2 Dec 2011 19:28:07 -0000 1.9 +++ files/patch-90_security 3 Dec 2012 22:02:54 -0000 @@ -15,7 +15,7 @@ Index: qemu/hw/dma.c } Index: qemu/hw/fdc.c -@@ -1322,7 +1322,8 @@ +@@ -1445,7 +1445,8 @@ static uint32_t fdctrl_read_data(FDCtrl fd_sector(cur_drv)); return 0; } @@ -25,16 +25,16 @@ Index: qemu/hw/fdc.c FLOPPY_DPRINTF("error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ -@@ -1776,7 +1777,8 @@ +@@ -1905,7 +1906,8 @@ static void fdctrl_write_data(FDCtrl *fd if (pos == FD_SECTOR_LEN - 1 || fdctrl->data_pos == fdctrl->data_len) { cur_drv = get_cur_drv(fdctrl); - if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { + if (cur_drv->bs == NULL || + bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv)); + FLOPPY_DPRINTF("error writing sector %d\n", + fd_sector(cur_drv)); return; - } Index: qemu-0.8.2/hw/sb16.c =================================================================== --- qemu-0.8.2.orig/hw/sb16.c 2006-07-22 20:23:34.000000000 +0300 Index: files/patch-Makefile =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-Makefile,v retrieving revision 1.12 diff -u -p -r1.12 patch-Makefile --- files/patch-Makefile 19 Jul 2012 20:15:43 -0000 1.12 +++ files/patch-Makefile 3 Dec 2012 22:12:14 -0000 @@ -1,5 +1,5 @@ Index: qemu/Makefile -@@ -40,7 +40,11 @@ LIBS+=-lz $(LIBS_TOOLS) +@@ -53,7 +53,11 @@ LIBS+=-lz $(LIBS_TOOLS) HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF) ifdef BUILD_DOCS @@ -11,7 +11,7 @@ Index: qemu/Makefile ifdef CONFIG_VIRTFS DOCS+=fsdev/virtfs-proxy-helper.1 endif -@@ -270,8 +274,10 @@ endif +@@ -311,8 +315,10 @@ endif install-doc: $(DOCS) $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" @@ -22,7 +22,7 @@ Index: qemu/Makefile ifdef CONFIG_POSIX $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1" -@@ -290,7 +296,10 @@ install-confdir: +@@ -331,7 +337,10 @@ install-confdir: $(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)" install-sysconfig: install-datadir install-confdir @@ -31,6 +31,6 @@ Index: qemu/Makefile + if [ ! -f "$(qemu_confdir)/target-x86_64.conf" ]; then \ + $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(qemu_confdir)"; \ + fi - $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/cpus-x86_64.conf "$(DESTDIR)$(qemu_datadir)" install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig install-datadir + $(INSTALL_DIR) "$(DESTDIR)$(bindir)" Index: files/patch-bg =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-bg,v retrieving revision 1.12 diff -u -p -r1.12 patch-bg --- files/patch-bg 9 Jun 2012 16:19:05 -0000 1.12 +++ files/patch-bg 16 Feb 2013 20:21:03 -0000 @@ -1,4 +1,4 @@ -Index: qemu/net.h +Index: qemu/include/net/net.h @@ -174,8 +174,8 @@ void net_host_device_remove(Monitor *mon int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data); @@ -10,7 +10,7 @@ Index: qemu/net.h #define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper" #define DEFAULT_BRIDGE_INTERFACE "br0" -Index: qemu/net/tap.h +Index: qemu/net/tap_int.h @@ -29,8 +29,8 @@ #include "qemu-common.h" #include "qemu-option.h" Index: files/patch-bsd-user-ld =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-bsd-user-ld,v retrieving revision 1.4 diff -u -p -r1.4 patch-bsd-user-ld --- files/patch-bsd-user-ld 13 Oct 2011 19:08:30 -0000 1.4 +++ files/patch-bsd-user-ld 16 Feb 2013 20:22:17 -0000 @@ -1,5 +1,5 @@ ---- a/x86_64.ld -+++ b/x86_64.ld +--- a/ldscripts/x86_64.ld ++++ b/ldscripts/x86_64.ld @@ -1,54 +1,58 @@ -/* Default linker script, for normal executables */ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") @@ -256,8 +256,8 @@ + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } } ---- a/i386.ld -+++ b/i386.ld +--- a/ldscripts/i386.ld ++++ b/ldscripts/i386.ld @@ -1,45 +1,47 @@ -/* ld script to make i386 Linux kernel - * Written by Martin Mares ; Index: files/patch-e1000-rx =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-e1000-rx,v retrieving revision 1.1 diff -u -p -r1.1 patch-e1000-rx --- files/patch-e1000-rx 1 Jun 2012 20:49:50 -0000 1.1 +++ files/patch-e1000-rx 3 Dec 2012 22:02:54 -0000 @@ -1,133 +0,0 @@ -Message-ID: <4FC741F1.4000905@redhat.com> -Date: Thu, 31 May 2012 12:03:29 +0200 -From: Paolo Bonzini -To: Jan Kiszka -References: <20120530202311.GA1768@onelab2.iet.unipi.it> - <20120530212333.GD2672@onelab2.iet.unipi.it> - <4FC69389.8050404@web.de> - - <4FC69B28.1000106@web.de> - - <4FC71FEB.9030100@redhat.com> <4FC72A95.4040808@web.de> -In-Reply-To: <4FC72A95.4040808@web.de> -Cc: Luigi Rizzo , rizzo@iet.unipi.it, - qemu-devel@nongnu.org, - Stefano Stabellini -Subject: Re: [Qemu-devel] Proposed patch: huge RX speedup for hw/e1000.c - -Il 31/05/2012 10:23, Jan Kiszka ha scritto: ->> > @@ -922,6 +923,7 @@ set_rdt(E1000State *s, int index, uint32_t val) ->> > { ->> > s->check_rxov = 0; ->> > s->mac_reg[index] = val & 0xffff; ->> > + qemu_notify_event(); -> This still looks like the wrong tool: Packets that can't be delivered -> are queued. - -Packets that are read from the tap but can't be delivered are queued; -packets that are left on the tap need qemu_notify_event to be flushed. - -> So we need to flush the queue and clear the blocked delivery -> there. qemu_flush_queued_packets appears more appropriate for this. - -Right, and qemu_flush_queued_packets needs to call qemu_notify_event -which makes the call in virtio-net unnecessary. - -Paolo - -diff --git a/hw/e1000.c b/hw/e1000.c -index 4573f13..43d933a 100644 ---- a/hw/e1000.c -+++ b/hw/e1000.c -@@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) - s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; - DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], - s->mac_reg[RCTL]); -+ qemu_flush_queued_packets(&s->nic->nc); - } - - static void -@@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val) - { - s->check_rxov = 0; - s->mac_reg[index] = val & 0xffff; -+ if (e1000_has_rxbufs(s, 1)) { -+ qemu_flush_queued_packets(&s->nic->nc); -+ } - } - - static void -diff --git a/hw/virtio-net.c b/hw/virtio-net.c -index 3f190d4..0974945 100644 ---- a/hw/virtio-net.c -+++ b/hw/virtio-net.c -@@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) - VirtIONet *n = to_virtio_net(vdev); - - qemu_flush_queued_packets(&n->nic->nc); -- -- /* We now have RX buffers, signal to the IO thread to break out of the -- * select to re-poll the tap file descriptor */ -- qemu_notify_event(); - } - - static int virtio_net_can_receive(VLANClientState *nc) -diff --git a/net.c b/net.c -index 1922d8a..fa846ae 100644 ---- a/net.c -+++ b/net.c -@@ -491,7 +491,12 @@ void qemu_flush_queued_packets(VLANClientState *vc) - queue = vc->send_queue; - } - -- qemu_net_queue_flush(queue); -+ if (qemu_net_queue_flush(queue)) { -+ /* We emptied the queue successfully, signal to the IO thread to repoll -+ * the file descriptor (for tap, for example). -+ */ -+ qemu_notify_event(); -+ } - } - - static ssize_t qemu_send_packet_async_with_flags(VLANClientState *sender, -diff --git a/net/queue.c b/net/queue.c -index 1ab5247..fd1c7e6 100644 ---- a/net/queue.c -+++ b/net/queue.c -@@ -232,7 +232,7 @@ void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from) - } - } - --void qemu_net_queue_flush(NetQueue *queue) -+bool qemu_net_queue_flush(NetQueue *queue) - { - while (!QTAILQ_EMPTY(&queue->packets)) { - NetPacket *packet; -@@ -248,7 +248,7 @@ void qemu_net_queue_flush(NetQueue *queue) - packet->size); - if (ret == 0) { - QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); -- break; -+ return 0; - } - - if (packet->sent_cb) { -@@ -257,4 +257,5 @@ void qemu_net_queue_flush(NetQueue *queue) - - g_free(packet); - } -+ return 1; - } -diff --git a/net/queue.h b/net/queue.h -index a31958e..4bf6d3c 100644 ---- a/net/queue.h -+++ b/net/queue.h -@@ -66,6 +66,6 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue, - NetPacketSent *sent_cb); - - void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from); --void qemu_net_queue_flush(NetQueue *queue); -+bool qemu_net_queue_flush(NetQueue *queue); - - #endif /* QEMU_NET_QUEUE_H */ - Index: files/patch-hw-ppc_newworld.c =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-hw-ppc_newworld.c,v retrieving revision 1.1 diff -u -p -r1.1 patch-hw-ppc_newworld.c --- files/patch-hw-ppc_newworld.c 21 Aug 2011 15:49:39 -0000 1.1 +++ files/patch-hw-ppc_newworld.c 16 Feb 2013 20:55:44 -0000 @@ -1,5 +1,5 @@ ---- a/hw/ppc_newworld.c -+++ b/hw/ppc_newworld.c +--- a/hw/ppc/mac_newworld.c ++++ b/hw/ppc/mac_newworld.c @@ -68,6 +68,11 @@ #include "hw/usb.h" #include "blockdev.h" Index: files/patch-hw-ppc_oldworld.c =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-hw-ppc_oldworld.c,v retrieving revision 1.1 diff -u -p -r1.1 patch-hw-ppc_oldworld.c --- files/patch-hw-ppc_oldworld.c 21 Aug 2011 15:49:39 -0000 1.1 +++ files/patch-hw-ppc_oldworld.c 16 Feb 2013 20:55:54 -0000 @@ -1,5 +1,5 @@ ---- a/hw/ppc_oldworld.c -+++ b/hw/ppc_oldworld.c +--- a/hw/ppc/mac_oldworld.c ++++ b/hw/ppc/mac_oldworld.c @@ -47,6 +47,11 @@ #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 Index: files/patch-ppc.ld =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-ppc.ld,v retrieving revision 1.2 diff -u -p -r1.2 patch-ppc.ld --- files/patch-ppc.ld 13 Oct 2011 19:08:30 -0000 1.2 +++ files/patch-ppc.ld 16 Feb 2013 20:24:27 -0000 @@ -1,5 +1,5 @@ ---- a/ppc.ld -+++ b/ppc.ld +--- a/ldscripts/ppc.ld ++++ b/ldscripts/ppc.ld @@ -99,7 +99,7 @@ SECTIONS PROVIDE (__init_array_start = .); KEEP (*(SORT(.init_array.*))) Index: files/patch-tapclose =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-tapclose,v retrieving revision 1.2 diff -u -p -r1.2 patch-tapclose --- files/patch-tapclose 1 Apr 2011 19:30:21 -0000 1.2 +++ files/patch-tapclose 16 Feb 2013 20:26:50 -0000 @@ -1,13 +1,13 @@ Index: qemu/net/tap.c -@@ -287,12 +287,13 @@ static void tap_cleanup(VLANClientState +@@ -286,12 +286,13 @@ static void tap_cleanup(NetClientState * qemu_purge_queued_packets(nc); - if (s->down_script[0]) - launch_script(s->down_script, s->down_script_arg, s->fd); - - tap_read_poll(s, 0); - tap_write_poll(s, 0); + tap_read_poll(s, false); + tap_write_poll(s, false); close(s->fd); + + if (s->down_script[0]) Index: files/patch-z-arm-bsd-user-001 =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/patch-z-arm-bsd-user-001,v retrieving revision 1.1 diff -u -p -r1.1 patch-z-arm-bsd-user-001 --- files/patch-z-arm-bsd-user-001 19 Jul 2012 20:15:43 -0000 1.1 +++ files/patch-z-arm-bsd-user-001 3 Dec 2012 22:02:54 -0000 @@ -289,6 +289,18 @@ #endif --- a/bsd-user/syscall.c.orig +++ b/bsd-user/syscall.c +@@ -96,6 +96,11 @@ static abi_long do_obreak(abi_ulong new_ + return 0; + } + ++abi_long do_brk(abi_ulong new_brk) ++{ ++ return do_obreak(new_brk); ++} ++ + #if defined(TARGET_I386) + static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms) + { @@ -157,6 +161,12 @@ static abi_long do_freebsd_sysarch(void } #endif Index: files/pcap-patch =================================================================== RCS file: /home/pcvs/ports/emulators/qemu-devel/files/pcap-patch,v retrieving revision 1.10 diff -u -p -r1.10 pcap-patch --- files/pcap-patch 9 Jun 2012 16:19:05 -0000 1.10 +++ files/pcap-patch 19 Mar 2013 19:20:31 -0000 @@ -1,31 +1,33 @@ ---- configure.orig 2010-01-29 14:36:00.000000000 -0500 -+++ configure 2010-01-29 14:36:00.000000000 -0500 -@@ -194,6 +194,9 @@ zlib="yes" - guest_agent="yes" - libiscsi="" - coroutine="" +--- configure.orig ++++ configure +@@ -226,6 +226,9 @@ coroutine="" + seccomp="" + glusterfs="" + virtio_blk_data_plane="" +pcap="no" +pcap_create="no" +bpf="no" # parse CC options first for opt do -@@ -670,6 +673,8 @@ for opt do +@@ -729,6 +732,10 @@ for opt do ;; - --enable-vnc-thread) vnc_thread="yes" + --enable-vnc-ws) vnc_ws="yes" ;; + --enable-pcap) pcap="yes" + ;; ++ --disable-pcap) pcap="no" ++ ;; --disable-slirp) slirp="no" ;; --disable-uuid) uuid="no" -@@ -1619,6 +1624,49 @@ EOF +@@ -1730,6 +1737,51 @@ EOF fi ########################################## +# pcap probe + -+if test "$pcap" = "yes" ; then ++if test "$pcap" = "yes" -a "$pcap" != "no"; then + cat > $TMPC << EOF +#include +int main(void) { return (pcap_lib_version() == (char *)0 ? 1 : 0); } @@ -35,7 +37,9 @@ + else + libpcap=-lwpcap + fi -+ if ! $cc $ARCH_CFLAGS -o $TMPE $libpcap $TMPC 2> /dev/null ; then ++ if compile_prog "$libpcap" ; then ++ : ++ else + echo + echo "Error: Could not find pcap" + echo "Make sure to have the pcap libs and headers installed." @@ -50,7 +54,7 @@ + return (pcap_create("foo", errbuf) == (pcap_t *)0 ? 1 : 0); +} +EOF -+ if $cc $ARCH_CFLAGS -o $TMPE $libpcap $TMPC 2> /dev/null ; then ++ if compile_prog "$libpcap" ; then + pcap_create="yes" + fi + cat > $TMPC << EOF @@ -59,17 +63,25 @@ +#include +int main(void) { return (BPF_MAJOR_VERSION); } +EOF -+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then ++ if compile_prog ; then + bpf="yes" + fi + libs_softmmu="$libpcap $libs_softmmu" +fi # test "$pcap" + +########################################## - # VNC TLS detection - if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then + # VNC TLS/WS detection + if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then cat > $TMPC <> $config_host_mak fi @@ -85,20 +97,33 @@ if test "$slirp" = "yes" ; then echo "CONFIG_SLIRP=y" >> $config_host_mak echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak -Index: net.c -@@ -37,6 +37,11 @@ - #include "hw/qdev.h" - #include "iov.h" +Index: net/clients.h +@@ -47,6 +47,11 @@ int net_init_tap(const NetClientOptions + int net_init_bridge(const NetClientOptions *opts, const char *name, + NetClientState *peer); + ++#ifdef CONFIG_PCAP ++int net_init_pcap(const NetClientOptions *opts, const char *name, ++ NetClientState *peer); ++#endif ++ + #ifdef CONFIG_VDE + int net_init_vde(const NetClientOptions *opts, const char *name, + NetClientState *peer); +Index: net/net.c +@@ -40,6 +40,11 @@ + #include "qapi/opts-visitor.h" + #include "qapi/dealloc-visitor.h" +#include +#ifdef __FreeBSD__ +#include +#endif + - static QTAILQ_HEAD(, VLANState) vlans; - static QTAILQ_HEAD(, VLANClientState) non_vlan_clients; - -@@ -797,6 +802,226 @@ static int net_init_nic(QemuOpts *opts, + /* Net bridge is currently not supported for W32. */ + #if !defined(_WIN32) + # define CONFIG_NET_BRIDGE +@@ -704,6 +709,221 @@ static int net_init_nic(const NetClientO return idx; } @@ -109,26 +134,27 @@ Index: net.c +#endif +#include + -+typedef struct PCAPState { -+ VLANClientState nc; -+ pcap_t *handle; -+ int max_eth_frame_size; -+} PCAPState; ++struct PCAPState { ++ NetClientState nc; ++ pcap_t *handle; ++ int max_eth_frame_size; ++}; + -+static ssize_t pcap_receive(VLANClientState *nc, const uint8_t *buf, size_t size) ++static ssize_t pcap_receive(NetClientState *nc, const uint8_t *buf, size_t size) +{ -+ PCAPState *s = DO_UPCAST(PCAPState, nc, nc); ++ struct PCAPState *s = DO_UPCAST(struct PCAPState, nc, nc); + + return pcap_inject(s->handle, (u_char*)buf, size); +} + -+static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata) ++static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata ++ ) +{ -+ VLANClientState *nc = (VLANClientState *)user; ++ NetClientState *nc = (NetClientState *)user; + + int len = phdr->len; +#ifdef __FreeBSD__ -+ PCAPState *s = DO_UPCAST(PCAPState, nc, nc); ++ struct PCAPState *s = DO_UPCAST(struct PCAPState, nc, nc); + int max_eth_frame_size = s->max_eth_frame_size; + + if (len > max_eth_frame_size) { @@ -143,7 +169,7 @@ Index: net.c + +static void pcap_send(void *opaque) +{ -+ PCAPState *s = (PCAPState *)opaque; ++ struct PCAPState *s = (struct PCAPState *)opaque; + + for (;;) { + if (pcap_dispatch(s->handle, 0, (pcap_handler)&pcap_callback, (u_char *)&s->nc) >= 0) @@ -151,37 +177,48 @@ Index: net.c + } +} + -+static void pcap_cleanup(VLANClientState *nc) ++static void pcap_cleanup(NetClientState *nc) +{ -+ PCAPState *s = DO_UPCAST(PCAPState, nc, nc); ++ struct PCAPState *s = DO_UPCAST(struct PCAPState, nc, nc); + ++ qemu_purge_queued_packets(nc); + pcap_close(s->handle); +} + +static NetClientInfo net_pcap_info = { -+ .type = NET_CLIENT_TYPE_PCAP, -+ .size = sizeof(PCAPState), ++ .type = NET_CLIENT_OPTIONS_KIND_PCAP, ++ .size = sizeof(struct PCAPState), + .receive = pcap_receive, ++// .receive_raw = pcap_receive_raw, ++// .receive_iov = pcap_receive_iov, ++// .poll = pcap_poll, + .cleanup = pcap_cleanup, +}; ++/* ++ * ... -net pcap,ifname="..." ++ */ + -+static int net_pcap_init(VLANState *vlan, const char *model, const char *name, const char *ifname) ++int net_init_pcap(const NetClientOptions *opts, const char *name, NetClientState *peer) +{ -+ VLANClientState *nc; -+ PCAPState *s = NULL; ++ const NetdevPcapOptions *pcap_opts = opts->pcap; ++ NetClientState *nc; ++ struct PCAPState *s; ++ const char *ifname; + char errbuf[PCAP_ERRBUF_SIZE]; +#if defined(_WIN32) + HANDLE h; +#endif + int i; + -+ s = g_malloc0(sizeof(PCAPState)); -+ nc = qemu_new_net_client(&net_pcap_info, vlan, NULL, model, name); -+ -+ s = DO_UPCAST(PCAPState, nc, nc); -+ if (!s) ++ if (!pcap_opts->has_ifname) + return -1; + ++ ifname = pcap_opts->ifname; ++ ++ /* create the object */ ++ nc = qemu_new_net_client(&net_pcap_info, peer, "pcap", ifname); ++ s = DO_UPCAST(struct PCAPState, nc, nc); ++ + if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) { + fprintf(stderr, "qemu: pcap_create: %s\n", errbuf); + goto fail; @@ -206,6 +243,7 @@ Index: net.c + close(i); + } +#endif ++ +#if defined(CONFIG_PCAP_CREATE) || defined(_WIN32) + /* + * Create pcap handle for the device, set promiscuous mode and activate. @@ -260,7 +298,6 @@ Index: net.c + } + } +#endif /* BIOCIMMEDIATE */ -+ +#if defined(BIOCFEEDBACK) + /* + * Tell the kernel that the sent packet has to be fed back. @@ -299,72 +336,43 @@ Index: net.c + if (s) { + if (s->handle) + pcap_close(s->handle); -+ g_free(s); + } + + return -1; +} + -+static int net_init_pcap(QemuOpts *opts, -+ Monitor *mon, -+ const char *name, -+ VLANState *vlan) -+{ -+ const char *ifname; -+ -+ ifname = qemu_opt_get(opts, "ifname"); -+ -+ if (net_pcap_init(vlan, "pcap", name, ifname) == -1) { -+ return -1; -+ } -+ -+ return 0; -+} -+#endif /* CONFIG_PCAP */ -+ - #define NET_COMMON_PARAMS_DESC \ - { \ - .name = "type", \ -@@ -973,6 +1198,21 @@ static const struct { - { /* end of list */ } - }, - }, -+#ifdef CONFIG_PCAP -+ [NET_CLIENT_TYPE_PCAP] = { -+ .type = "pcap", -+ .init = net_init_pcap, -+ .desc = { -+ NET_COMMON_PARAMS_DESC, -+ { -+ .name = "ifname", -+ .type = QEMU_OPT_STRING, -+ .help = "interface name", -+ }, -+ { /* end of list */ } -+ }, -+ }, +#endif - [NET_CLIENT_TYPE_SOCKET] = { - .type = "socket", - .init = net_init_socket, -@@ -1343,6 +1583,7 @@ void net_check_clients(void) - case NET_CLIENT_TYPE_TAP: - case NET_CLIENT_TYPE_SOCKET: - case NET_CLIENT_TYPE_VDE: -+ case NET_CLIENT_TYPE_PCAP: - has_host_dev = 1; - break; - default: ; ---- qemu-options.hx.orig 2010-01-14 17:18:00.000000000 -0500 -+++ qemu-options.hx 2010-01-29 14:36:00.000000000 -0500 -@@ -799,6 +799,10 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "") - DEF("net", HAS_ARG, QEMU_OPTION_net, - "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n" - " create a new Network Interface Card and connect it to VLAN 'n'\n" + + static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])( + const NetClientOptions *opts, +@@ -722,6 +944,9 @@ static int (* const net_client_init_fun[ + #ifdef CONFIG_NET_BRIDGE + [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge, + #endif +#ifdef CONFIG_PCAP -+ "-net pcap[,vlan=n][,name=str][,ifname=name]\n" -+ " connect the host network interface using PCAP to VLAN 'n'\n" ++ [NET_CLIENT_OPTIONS_KIND_PCAP] = net_init_pcap, +#endif - #ifdef CONFIG_SLIRP - "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n" - " [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n" + [NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport, + }; + +--- qapi-schema.json.orig ++++ qapi-schema.json +@@ -2622,6 +2622,10 @@ + '*br': 'str', + '*helper': 'str' } } + ++{ 'type': 'NetdevPcapOptions', ++ 'data': { ++ '*ifname': 'str' } } ++ + ## + # @NetdevHubPortOptions + # +@@ -2648,6 +2652,7 @@ + 'nic': 'NetLegacyNicOptions', + 'user': 'NetdevUserOptions', + 'tap': 'NetdevTapOptions', ++ 'pcap': 'NetdevPcapOptions', + 'socket': 'NetdevSocketOptions', + 'vde': 'NetdevVdeOptions', + 'dump': 'NetdevDumpOptions', Index: files/patch-bsd-user-qemu.h @@ -0,0 +1,31 @@ +--- a/bsd-user/qemu.h ++++ b/bsd-user/qemu.h +@@ -50,6 +50,10 @@ struct image_info { + abi_ulong entry; + abi_ulong code_offset; + abi_ulong data_offset; ++#if 1 ++ abi_ulong arg_start; ++ abi_ulong arg_end; ++#endif + int personality; + }; + +@@ -72,6 +76,17 @@ struct emulated_sigtable { + typedef struct TaskState { + struct TaskState *next; + int used; /* non zero if used */ ++#if 1 ++#ifdef TARGET_ARM ++ int swi_errno; ++#endif ++#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) ++ /* Extra fields for semihosted binaries. */ ++ uint32_t heap_base; ++ uint32_t heap_limit; ++#endif ++ uint32_t stack_base; ++#endif + struct image_info *info; + + struct emulated_sigtable sigtab[TARGET_NSIG]; Index: files/patch-z2-bsd-user-cognet-sson-002 @@ -0,0 +1,8355 @@ +#diff --git a/Makefile b/Makefile +#index 5fa0f1d..55e151e 100644 +#--- a/Makefile +#+++ b/Makefile +#@@ -65,7 +65,8 @@ CLANG_CFLAGS_AS+= -no-integrated-as +# +# .if ${PORT_OPTIONS:MX86_TARGETS} +# .if ${PORT_OPTIONS:MBSD_USER} +#-CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,x86_64-bsd-user,sparc-bsd-user,sparc64-bsd-user,arm-bsd-user +#+#CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu,i386-bsd-user,x86_64-bsd-user,sparc-bsd-user,sparc64-bsd-user,arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user +#+CONFIGURE_ARGS+= --target-list=arm-bsd-user,armeb-bsd-user,mips-bsd-user,mipsel-bsd-user,mips64-bsd-user +# .else +# CONFIGURE_ARGS+= --target-list=i386-softmmu,x86_64-softmmu +# .endif +#@@ -106,6 +107,8 @@ CONFIGURE_ARGS+= --prefix=${PREFIX} --cc=${CC} --enable-docs \ +# --disable-linux-user --disable-linux-aio \ +# --disable-kvm --disable-xen \ +# --smbd=${LOCALBASE}/sbin/smbd \ +#+ --enable-debug \ +#+ --enable-debug-info \ +# --extra-cflags=-I${WRKSRC}\ -I${LOCALBASE}/include\ -DPREFIX=\\\"${PREFIX}\\\" +# +# .if empty(PORT_OPTIONS:MSDL) +diff --git a/bsd-user/arm/target_signal.h b/bsd-user/arm/target_signal.h +index 1b644cc..19cc188 100644 +--- a/bsd-user/arm/target_signal.h ++++ b/bsd-user/arm/target_signal.h +@@ -3,17 +3,12 @@ + + #include "cpu.h" + +-/* this struct defines a stack used during syscall handling */ +- +-typedef struct target_sigaltstack { +- abi_ulong ss_sp; +- abi_long ss_flags; +- abi_ulong ss_size; +-} target_stack_t; +- + static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) + { + return state->regs[13]; + } + ++#define TARGET_MINSIGSTKSZ (1024 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/arm/target_vmparam.h b/bsd-user/arm/target_vmparam.h +new file mode 100644 +index 0000000..0427244 +--- /dev/null ++++ b/bsd-user/arm/target_vmparam.h +@@ -0,0 +1,28 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#if defined(__FreeBSD__) ++ /* KERNBASE - 512 MB */ ++#define TARGET_VM_MAXUSER_ADDRESS (0xc0000000 - (512 * 1024 * 1024)) ++#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS ++ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#define TARGET_SZSIGCODE 0 ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++#endif ++ ++#endif /* _TARGET_VMPARAM_H_ */ +diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c +index 2abc713..dcf6f66 100644 +--- a/bsd-user/bsdload.c ++++ b/bsd-user/bsdload.c +@@ -53,7 +53,7 @@ static int count(char ** vec) + return(i); + } + +-static int prepare_binprm(struct linux_binprm *bprm) ++static int prepare_binprm(struct bsd_binprm *bprm) + { + struct stat st; + int mode; +@@ -155,33 +155,33 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + } + + int loader_exec(const char * filename, char ** argv, char ** envp, +- struct target_pt_regs * regs, struct image_info *infop) ++ struct target_pt_regs * regs, struct image_info *infop, ++ struct bsd_binprm *bprm) + { +- struct linux_binprm bprm; + int retval; + int i; + +- bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); ++ bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES /*-sizeof(unsigned int) XXX */; + for (i=0 ; ipage[i] = NULL; + retval = open(filename, O_RDONLY); + if (retval < 0) + return retval; +- bprm.fd = retval; +- bprm.filename = (char *)filename; +- bprm.argc = count(argv); +- bprm.argv = argv; +- bprm.envc = count(envp); +- bprm.envp = envp; ++ bprm->fd = retval; ++ bprm->filename = (char *)filename; ++ bprm->argc = count(argv); ++ bprm->argv = argv; ++ bprm->envc = count(envp); ++ bprm->envp = envp; + +- retval = prepare_binprm(&bprm); ++ retval = prepare_binprm(bprm); + + if(retval>=0) { +- if (bprm.buf[0] == 0x7f +- && bprm.buf[1] == 'E' +- && bprm.buf[2] == 'L' +- && bprm.buf[3] == 'F') { +- retval = load_elf_binary(&bprm,regs,infop); ++ if (bprm->buf[0] == 0x7f ++ && bprm->buf[1] == 'E' ++ && bprm->buf[2] == 'L' ++ && bprm->buf[3] == 'F') { ++ retval = load_elf_binary(bprm,regs,infop); + } else { + fprintf(stderr, "Unknown binary format\n"); + return -1; +@@ -196,7 +196,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, + + /* Something went wrong, return the inode and free the argument pages*/ + for (i=0 ; ipage[i]); + } + return(retval); + } +diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c +index 993dcf7..15cf3a6 100644 +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -9,6 +9,8 @@ + #include + #include + ++#include ++ + #include "qemu.h" + #include "disas.h" + +@@ -93,6 +95,7 @@ enum { + + #ifdef TARGET_I386 + ++#ifndef __FreeBSD__ + #define ELF_PLATFORM get_elf_platform() + + static const char *get_elf_platform(void) +@@ -112,6 +115,7 @@ static uint32_t get_elf_hwcap(void) + { + return thread_env->cpuid_features; + } ++#endif /* ! __FreeBSD__ */ + + #ifdef TARGET_X86_64 + #define ELF_START_MMAP 0x2aaaaab000ULL +@@ -378,13 +382,14 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * + + #ifdef TARGET_MIPS + +-#define ELF_START_MMAP 0x80000000 + + #define elf_check_arch(x) ( (x) == EM_MIPS ) + +-#ifdef TARGET_MIPS64 ++#if defined(TARGET_MIPS64) ++#define ELF_START_MMAP 0x2aaaaab000ULL + #define ELF_CLASS ELFCLASS64 + #else ++#define ELF_START_MMAP 0x80000000 + #define ELF_CLASS ELFCLASS32 + #endif + #ifdef TARGET_WORDS_BIGENDIAN +@@ -396,9 +401,10 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * + + static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) + { ++ + regs->cp0_status = 2 << CP0St_KSU; +- regs->cp0_epc = infop->entry; +- regs->regs[29] = infop->start_stack; ++ regs->regs[25] = regs->cp0_epc = infop->entry; /* t9 = pc = entry */ ++ regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0 = sp = start_stack */ + } + + #define USE_ELF_CORE_DUMP +@@ -576,30 +582,38 @@ static void bswap_ehdr(struct elfhdr *ehdr) + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ + } + +-static void bswap_phdr(struct elf_phdr *phdr) ++static void bswap_phdr(struct elf_phdr *phdr, int phnum) + { +- bswap32s(&phdr->p_type); /* Segment type */ +- bswaptls(&phdr->p_offset); /* Segment file offset */ +- bswaptls(&phdr->p_vaddr); /* Segment virtual address */ +- bswaptls(&phdr->p_paddr); /* Segment physical address */ +- bswaptls(&phdr->p_filesz); /* Segment size in file */ +- bswaptls(&phdr->p_memsz); /* Segment size in memory */ +- bswap32s(&phdr->p_flags); /* Segment flags */ +- bswaptls(&phdr->p_align); /* Segment alignment */ ++ int i; ++ ++ for (i = 0; i < phnum; ++i, ++phdr) { ++ bswap32s(&phdr->p_type); /* Segment type */ ++ bswap32s(&phdr->p_flags); /* Segment flags */ ++ bswaptls(&phdr->p_offset); /* Segment file offset */ ++ bswaptls(&phdr->p_vaddr); /* Segment virtual address */ ++ bswaptls(&phdr->p_paddr); /* Segment physical address */ ++ bswaptls(&phdr->p_filesz); /* Segment size in file */ ++ bswaptls(&phdr->p_memsz); /* Segment size in memory */ ++ bswaptls(&phdr->p_align); /* Segment alignment */ ++ } + } + +-static void bswap_shdr(struct elf_shdr *shdr) ++static void bswap_shdr(struct elf_shdr *shdr, int shnum) + { +- bswap32s(&shdr->sh_name); +- bswap32s(&shdr->sh_type); +- bswaptls(&shdr->sh_flags); +- bswaptls(&shdr->sh_addr); +- bswaptls(&shdr->sh_offset); +- bswaptls(&shdr->sh_size); +- bswap32s(&shdr->sh_link); +- bswap32s(&shdr->sh_info); +- bswaptls(&shdr->sh_addralign); +- bswaptls(&shdr->sh_entsize); ++ int i; ++ ++ for (i = 0; i < shnum; ++i, ++shdr) { ++ bswap32s(&shdr->sh_name); ++ bswap32s(&shdr->sh_type); ++ bswaptls(&shdr->sh_flags); ++ bswaptls(&shdr->sh_addr); ++ bswaptls(&shdr->sh_offset); ++ bswaptls(&shdr->sh_size); ++ bswap32s(&shdr->sh_link); ++ bswap32s(&shdr->sh_info); ++ bswaptls(&shdr->sh_addralign); ++ bswaptls(&shdr->sh_entsize); ++ } + } + + static void bswap_sym(struct elf_sym *sym) +@@ -609,7 +623,14 @@ static void bswap_sym(struct elf_sym *sym) + bswaptls(&sym->st_size); + bswap16s(&sym->st_shndx); + } +-#endif ++ ++#else /* ! BSWAP_NEEDED */ ++ ++static inline void bswap_ehdr(struct elfhdr *ehdr) { } ++static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { } ++static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { } ++static inline void bswap_sym(struct elf_sym *sym) { } ++#endif /* ! BSWAP_NEEDED */ + + /* + * 'copy_elf_strings()' copies argument/envelope strings from user +@@ -666,7 +687,26 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, + return p; + } + +-static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, ++#if defined(TARGET_MIPS64) ++static inline int ++install_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned syscall) ++{ ++ int i; ++ uint32_t sigtramp_code[] = { ++ 0x67A40000 + sigf_uc, /* daddu $a0, $sp, (sigf_uc) */ ++ 0x24020000 + syscall, /* li $v0, (syscall) */ ++ 0x0000000C, /* syscall */ ++ 0x0000000D /* break */ ++ }; ++ ++ for(i = 0; i < 4; i++) ++ tswap32s(&sigtramp_code[i]); ++ ++ return (memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE)); ++} ++#endif ++ ++static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + struct image_info *info) + { + abi_ulong stack_base, size, error; +@@ -678,7 +718,13 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, + size = x86_stack_size; + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; +- error = target_mmap(0, ++ ++#ifdef TARGET_USRSTACK ++ stack_base = TARGET_USRSTACK - size; ++#else ++ stack_base = (abi_ulong)0; ++#endif ++ error = target_mmap(stack_base, + size + qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, +@@ -690,6 +736,113 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, + /* we reserve one extra page at the top of the stack as guard */ + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); + ++#if defined(__FreeBSD__) ++ /* ++ * The inital FreeBSD stack looks like follows: ++ * (see kern/kern_exec.c exec_copyout_strings() ) ++ * ++ * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.) ++ * unsigned ps_nargvstr ++ * char **ps_envstr ++ * PS_STRINGS -> unsigned ps_nenvstr ++ * ++ * machine dependent sigcode (sv_sigcode of size ++ * sv_szsigcode) ++ * ++ * execpath (absolute image path for rtld) ++ * ++ * SSP Canary (sizeof(long) * 8) ++ * ++ * page sizes array (usually sizeof(u_long) ) ++ * ++ * "destp" -> argv, env strings (up to 262144 bytes) ++ */ ++ ++ { ++ abi_ulong stack_hi_addr; ++ size_t execpath_len; ++ abi_ulong destp; ++ struct target_ps_strings ps_strs; ++ char canary[sizeof(abi_long) * 8]; ++ char execpath[PATH_MAX]; ++ ++ stack_hi_addr = p = error + size; ++ ++ /* Save some space for ps_strings. */ ++ p -= sizeof(struct target_ps_strings); ++ ++#if TARGET_SZSIGCODE > 0 ++ /* Add machine depedent sigcode. */ ++ p -= TARGET_SZSIGCODE; ++ /* XXX - check return value of memcpy_to_target() for failure */ ++ install_sigtramp( p, (unsigned)offsetof(struct target_sigframe, ++ sf_uc), TARGET_FREEBSD_NR_sigreturn); ++#endif ++ ++ /* Add execpath for rtld. */ ++ if (strlen(bprm->filename)) { ++ /* XXX - check return value of realpath() */ ++ realpath(bprm->filename, execpath); ++ execpath_len = strlen(execpath) + 1; ++ } else ++ execpath_len = 0; ++ ++ if (execpath_len) { ++ p -= roundup(execpath_len, sizeof(abi_ulong)); ++ /* XXX - check return value of memcpy_to_target() */ ++ memcpy_to_target(p, execpath, execpath_len); ++ } ++ ++ /* Add canary for SSP. */ ++ arc4random_buf(canary, sizeof(canary)); ++ p -= roundup(sizeof(canary), sizeof(abi_ulong)); ++ /* XXX - check return value of memcpy_to_target(). */ ++ memcpy_to_target(p, canary, sizeof(canary)); ++ ++ /* Add page sizes array. */ ++ p -= sizeof(abi_ulong); ++ /* XXX - check return value of put_user_ual(). */ ++ put_user_ual(TARGET_PAGE_SIZE, p); ++ ++ p = destp = p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX; ++ ++ /* XXX should check strlen(argv and envp strings) < TARGET_ARG_MAX */ ++ ++ /* ++ * Add argv strings. Note that the argv[] vectors are added by ++ * loader_build_argptr() ++ */ ++ i = bprm->argc; ++ while (i-- > 0) { ++ size_t len = strlen(bprm->argv[i]) + 1; ++ /* XXX - check return value of memcpy_to_target(). */ ++ memcpy_to_target(destp, bprm->argv[i], len); ++ destp += len; ++ } ++ ps_strs.ps_argvstr = tswapl(destp); ++ ps_strs.ps_nargvstr = tswap32(bprm->argc); ++ ++ /* ++ * Add env strings. Note that the envp[] vectors are added by ++ * loader_build_argptr(). ++ */ ++ i = bprm->envc; ++ while(i-- > 0) { ++ size_t len = strlen(bprm->envp[i]) + 1; ++ /* XXX - check return value of memcpy_to_target(). */ ++ memcpy_to_target(destp, bprm->envp[i], len); ++ destp += len; ++ } ++ ps_strs.ps_envstr = tswapl(destp); ++ ps_strs.ps_nenvstr = tswap32(bprm->envc); ++ ++ /* XXX - check return value of memcpy_to_target(). */ ++ memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs, ++ sizeof(ps_strs)); ++ } ++ ++#else ++ + stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + p += stack_base; + +@@ -702,6 +855,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, + } + stack_base += TARGET_PAGE_SIZE; + } ++#endif ++ + return p; + } + +@@ -769,11 +924,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + { + abi_ulong sp; + int size; ++#ifndef __FreeBSD__ + abi_ulong u_platform; + const char *k_platform; ++#endif + const int n = sizeof(elf_addr_t); + + sp = p; ++#ifndef __FreeBSD__ + u_platform = 0; + k_platform = ELF_PLATFORM; + if (k_platform) { +@@ -783,22 +941,28 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + /* FIXME - check return value of memcpy_to_target() for failure */ + memcpy_to_target(sp, k_platform, len); + } ++#endif /* ! __FreeBSD__ */ + /* + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (abi_ulong)15; ++#ifdef __FreeBSD__ ++ size = 0; ++#else + size = (DLINFO_ITEMS + 1) * 2; + if (k_platform) + size += 2; + #ifdef DLINFO_ARCH_ITEMS + size += DLINFO_ARCH_ITEMS * 2; + #endif ++#endif /* ! __FreeBSD__ */ + size += envc + argc + 2; + size += (!ibcs ? 3 : 1); /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); + ++#ifndef __FreeBSD__ + /* This is correct because Linux defines + * elf_addr_t as Elf32_Off / Elf64_Off + */ +@@ -833,6 +997,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + ARCH_DLINFO; + #endif + #undef NEW_AUX_ENT ++#endif /* ! __FreeBSD__ */ + + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); + return sp; +@@ -856,9 +1021,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + last_bss = 0; + error = 0; + +-#ifdef BSWAP_NEEDED + bswap_ehdr(interp_elf_ex); +-#endif + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || +@@ -899,12 +1062,7 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + free (elf_phdata); + return retval; + } +-#ifdef BSWAP_NEEDED +- eppnt = elf_phdata; +- for (i=0; ie_phnum; i++, eppnt++) { +- bswap_phdr(eppnt); +- } +-#endif ++ bswap_phdr(elf_phdata, interp_elf_ex->e_phnum); + + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid hardcoding the interpreter load +@@ -1049,9 +1207,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) + for (i = 0; i < hdr->e_shnum; i++) { + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; +-#ifdef BSWAP_NEEDED +- bswap_shdr(&sechdr); +-#endif ++ bswap_shdr(&sechdr, 1); + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff +@@ -1059,9 +1215,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; +-#ifdef BSWAP_NEEDED +- bswap_shdr(&strtab); +-#endif ++ bswap_shdr(&strtab, 1); + goto found; + } + } +@@ -1094,9 +1248,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) + + i = 0; + while (i < nsyms) { +-#ifdef BSWAP_NEEDED + bswap_sym(syms + i); +-#endif + // Throw away entries which we do not need. + if (syms[i].st_shndx == SHN_UNDEF || + syms[i].st_shndx >= SHN_LORESERVE || +@@ -1148,7 +1300,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) + syminfos = s; + } + +-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, ++int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) + { + struct elfhdr elf_ex; +@@ -1178,9 +1330,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + load_addr = 0; + load_bias = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ +-#ifdef BSWAP_NEEDED + bswap_ehdr(&elf_ex); +-#endif + + /* First of all, some simple consistency checks */ + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || +@@ -1188,12 +1338,14 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + return -ENOEXEC; + } + ++#ifndef __FreeBSD__ + bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); + bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + if (!bprm->p) { + retval = -E2BIG; + } ++#endif /* ! __FreeBSD__ */ + + /* Now read in all of the header information */ + elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); +@@ -1214,12 +1366,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + return -errno; + } + +-#ifdef BSWAP_NEEDED +- elf_ppnt = elf_phdata; +- for (i=0; ip_vaddr); ++ load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + } + + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), +@@ -1541,12 +1688,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + padzero(elf_bss, elf_brk); + + #if 0 +- printf("(start_brk) %x\n" , info->start_brk); +- printf("(end_code) %x\n" , info->end_code); +- printf("(start_code) %x\n" , info->start_code); +- printf("(end_data) %x\n" , info->end_data); +- printf("(start_stack) %x\n" , info->start_stack); +- printf("(brk) %x\n" , info->brk); ++ printf("(start_brk) 0x" TARGET_FMT_lx "\n" , info->start_brk); ++ printf("(end_code) 0x" TARGET_FMT_lx "\n" , info->end_code); ++ printf("(start_code) 0x" TARGET_FMT_lx "\n" , info->start_code); ++ printf("(start_data) 0x" TARGET_FMT_lx "\n" , info->start_data); ++ printf("(end_data) 0x" TARGET_FMT_lx "\n" , info->end_data); ++ printf("(start_stack) 0x" TARGET_FMT_lx "\n" , info->start_stack); ++ printf("(brk) 0x" TARGET_FMT_lx "\n" , info->brk); + #endif + + if ( info->personality == PER_SVR4 ) +@@ -1561,6 +1709,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + + info->entry = elf_entry; + ++#ifdef USE_ELF_CORE_DUMP ++ /* bprm->core_dump = &elf_core_dump; */ ++ bprm->core_dump = NULL; ++#endif ++ + return 0; + } + +diff --git a/bsd-user/freebsd/syscall_nr.h b/bsd-user/freebsd/syscall_nr.h +index 36336ab..e46571f 100644 +--- a/bsd-user/freebsd/syscall_nr.h ++++ b/bsd-user/freebsd/syscall_nr.h +@@ -1,373 +1,448 @@ + /* + * System call numbers. + * +- * $FreeBSD: src/sys/sys/syscall.h,v 1.224 2008/08/24 21:23:08 rwatson Exp $ +- * created from FreeBSD: head/sys/kern/syscalls.master 182123 2008-08-24 21:20:35Z rwatson ++ * created from FreeBSD: releng/9.1/sys/kern/syscalls.master 229723 2012-01-06 19:29:16Z jhb + */ + +-#define TARGET_FREEBSD_NR_syscall 0 +-#define TARGET_FREEBSD_NR_exit 1 +-#define TARGET_FREEBSD_NR_fork 2 +-#define TARGET_FREEBSD_NR_read 3 +-#define TARGET_FREEBSD_NR_write 4 +-#define TARGET_FREEBSD_NR_open 5 +-#define TARGET_FREEBSD_NR_close 6 +-#define TARGET_FREEBSD_NR_wait4 7 +-#define TARGET_FREEBSD_NR_link 9 +-#define TARGET_FREEBSD_NR_unlink 10 +-#define TARGET_FREEBSD_NR_chdir 12 +-#define TARGET_FREEBSD_NR_fchdir 13 +-#define TARGET_FREEBSD_NR_mknod 14 +-#define TARGET_FREEBSD_NR_chmod 15 +-#define TARGET_FREEBSD_NR_chown 16 +-#define TARGET_FREEBSD_NR_break 17 +-#define TARGET_FREEBSD_NR_freebsd4_getfsstat 18 +-#define TARGET_FREEBSD_NR_getpid 20 +-#define TARGET_FREEBSD_NR_mount 21 +-#define TARGET_FREEBSD_NR_unmount 22 +-#define TARGET_FREEBSD_NR_setuid 23 +-#define TARGET_FREEBSD_NR_getuid 24 +-#define TARGET_FREEBSD_NR_geteuid 25 +-#define TARGET_FREEBSD_NR_ptrace 26 +-#define TARGET_FREEBSD_NR_recvmsg 27 +-#define TARGET_FREEBSD_NR_sendmsg 28 +-#define TARGET_FREEBSD_NR_recvfrom 29 +-#define TARGET_FREEBSD_NR_accept 30 +-#define TARGET_FREEBSD_NR_getpeername 31 +-#define TARGET_FREEBSD_NR_getsockname 32 +-#define TARGET_FREEBSD_NR_access 33 +-#define TARGET_FREEBSD_NR_chflags 34 +-#define TARGET_FREEBSD_NR_fchflags 35 +-#define TARGET_FREEBSD_NR_sync 36 +-#define TARGET_FREEBSD_NR_kill 37 +-#define TARGET_FREEBSD_NR_getppid 39 +-#define TARGET_FREEBSD_NR_dup 41 +-#define TARGET_FREEBSD_NR_pipe 42 +-#define TARGET_FREEBSD_NR_getegid 43 +-#define TARGET_FREEBSD_NR_profil 44 +-#define TARGET_FREEBSD_NR_ktrace 45 +-#define TARGET_FREEBSD_NR_getgid 47 +-#define TARGET_FREEBSD_NR_getlogin 49 +-#define TARGET_FREEBSD_NR_setlogin 50 +-#define TARGET_FREEBSD_NR_acct 51 +-#define TARGET_FREEBSD_NR_sigaltstack 53 +-#define TARGET_FREEBSD_NR_ioctl 54 +-#define TARGET_FREEBSD_NR_reboot 55 +-#define TARGET_FREEBSD_NR_revoke 56 +-#define TARGET_FREEBSD_NR_symlink 57 +-#define TARGET_FREEBSD_NR_readlink 58 +-#define TARGET_FREEBSD_NR_execve 59 +-#define TARGET_FREEBSD_NR_umask 60 +-#define TARGET_FREEBSD_NR_chroot 61 +-#define TARGET_FREEBSD_NR_msync 65 +-#define TARGET_FREEBSD_NR_vfork 66 +-#define TARGET_FREEBSD_NR_sbrk 69 +-#define TARGET_FREEBSD_NR_sstk 70 +-#define TARGET_FREEBSD_NR_vadvise 72 +-#define TARGET_FREEBSD_NR_munmap 73 +-#define TARGET_FREEBSD_NR_mprotect 74 +-#define TARGET_FREEBSD_NR_madvise 75 +-#define TARGET_FREEBSD_NR_mincore 78 +-#define TARGET_FREEBSD_NR_getgroups 79 +-#define TARGET_FREEBSD_NR_setgroups 80 +-#define TARGET_FREEBSD_NR_getpgrp 81 +-#define TARGET_FREEBSD_NR_setpgid 82 +-#define TARGET_FREEBSD_NR_setitimer 83 +-#define TARGET_FREEBSD_NR_swapon 85 +-#define TARGET_FREEBSD_NR_getitimer 86 +-#define TARGET_FREEBSD_NR_getdtablesize 89 +-#define TARGET_FREEBSD_NR_dup2 90 +-#define TARGET_FREEBSD_NR_fcntl 92 +-#define TARGET_FREEBSD_NR_select 93 +-#define TARGET_FREEBSD_NR_fsync 95 +-#define TARGET_FREEBSD_NR_setpriority 96 +-#define TARGET_FREEBSD_NR_socket 97 +-#define TARGET_FREEBSD_NR_connect 98 +-#define TARGET_FREEBSD_NR_getpriority 100 +-#define TARGET_FREEBSD_NR_bind 104 +-#define TARGET_FREEBSD_NR_setsockopt 105 +-#define TARGET_FREEBSD_NR_listen 106 +-#define TARGET_FREEBSD_NR_gettimeofday 116 +-#define TARGET_FREEBSD_NR_getrusage 117 +-#define TARGET_FREEBSD_NR_getsockopt 118 +-#define TARGET_FREEBSD_NR_readv 120 +-#define TARGET_FREEBSD_NR_writev 121 +-#define TARGET_FREEBSD_NR_settimeofday 122 +-#define TARGET_FREEBSD_NR_fchown 123 +-#define TARGET_FREEBSD_NR_fchmod 124 +-#define TARGET_FREEBSD_NR_setreuid 126 +-#define TARGET_FREEBSD_NR_setregid 127 +-#define TARGET_FREEBSD_NR_rename 128 +-#define TARGET_FREEBSD_NR_flock 131 +-#define TARGET_FREEBSD_NR_mkfifo 132 +-#define TARGET_FREEBSD_NR_sendto 133 +-#define TARGET_FREEBSD_NR_shutdown 134 +-#define TARGET_FREEBSD_NR_socketpair 135 +-#define TARGET_FREEBSD_NR_mkdir 136 +-#define TARGET_FREEBSD_NR_rmdir 137 +-#define TARGET_FREEBSD_NR_utimes 138 +-#define TARGET_FREEBSD_NR_adjtime 140 +-#define TARGET_FREEBSD_NR_setsid 147 +-#define TARGET_FREEBSD_NR_quotactl 148 +-#define TARGET_FREEBSD_NR_nlm_syscall 154 +-#define TARGET_FREEBSD_NR_nfssvc 155 +-#define TARGET_FREEBSD_NR_freebsd4_statfs 157 +-#define TARGET_FREEBSD_NR_freebsd4_fstatfs 158 +-#define TARGET_FREEBSD_NR_lgetfh 160 +-#define TARGET_FREEBSD_NR_getfh 161 +-#define TARGET_FREEBSD_NR_getdomainname 162 +-#define TARGET_FREEBSD_NR_setdomainname 163 +-#define TARGET_FREEBSD_NR_uname 164 +-#define TARGET_FREEBSD_NR_sysarch 165 +-#define TARGET_FREEBSD_NR_rtprio 166 +-#define TARGET_FREEBSD_NR_semsys 169 +-#define TARGET_FREEBSD_NR_msgsys 170 +-#define TARGET_FREEBSD_NR_shmsys 171 +-#define TARGET_FREEBSD_NR_freebsd6_pread 173 +-#define TARGET_FREEBSD_NR_freebsd6_pwrite 174 +-#define TARGET_FREEBSD_NR_setfib 175 +-#define TARGET_FREEBSD_NR_ntp_adjtime 176 +-#define TARGET_FREEBSD_NR_setgid 181 +-#define TARGET_FREEBSD_NR_setegid 182 +-#define TARGET_FREEBSD_NR_seteuid 183 +-#define TARGET_FREEBSD_NR_stat 188 +-#define TARGET_FREEBSD_NR_fstat 189 +-#define TARGET_FREEBSD_NR_lstat 190 +-#define TARGET_FREEBSD_NR_pathconf 191 +-#define TARGET_FREEBSD_NR_fpathconf 192 +-#define TARGET_FREEBSD_NR_getrlimit 194 +-#define TARGET_FREEBSD_NR_setrlimit 195 +-#define TARGET_FREEBSD_NR_getdirentries 196 +-#define TARGET_FREEBSD_NR_freebsd6_mmap 197 +-#define TARGET_FREEBSD_NR___syscall 198 +-#define TARGET_FREEBSD_NR_freebsd6_lseek 199 +-#define TARGET_FREEBSD_NR_freebsd6_truncate 200 +-#define TARGET_FREEBSD_NR_freebsd6_ftruncate 201 +-#define TARGET_FREEBSD_NR___sysctl 202 +-#define TARGET_FREEBSD_NR_mlock 203 +-#define TARGET_FREEBSD_NR_munlock 204 +-#define TARGET_FREEBSD_NR_undelete 205 +-#define TARGET_FREEBSD_NR_futimes 206 +-#define TARGET_FREEBSD_NR_getpgid 207 +-#define TARGET_FREEBSD_NR_poll 209 +-#define TARGET_FREEBSD_NR___semctl 220 +-#define TARGET_FREEBSD_NR_semget 221 +-#define TARGET_FREEBSD_NR_semop 222 +-#define TARGET_FREEBSD_NR_msgctl 224 +-#define TARGET_FREEBSD_NR_msgget 225 +-#define TARGET_FREEBSD_NR_msgsnd 226 +-#define TARGET_FREEBSD_NR_msgrcv 227 +-#define TARGET_FREEBSD_NR_shmat 228 +-#define TARGET_FREEBSD_NR_shmctl 229 +-#define TARGET_FREEBSD_NR_shmdt 230 +-#define TARGET_FREEBSD_NR_shmget 231 +-#define TARGET_FREEBSD_NR_clock_gettime 232 +-#define TARGET_FREEBSD_NR_clock_settime 233 +-#define TARGET_FREEBSD_NR_clock_getres 234 +-#define TARGET_FREEBSD_NR_ktimer_create 235 +-#define TARGET_FREEBSD_NR_ktimer_delete 236 +-#define TARGET_FREEBSD_NR_ktimer_settime 237 +-#define TARGET_FREEBSD_NR_ktimer_gettime 238 +-#define TARGET_FREEBSD_NR_ktimer_getoverrun 239 +-#define TARGET_FREEBSD_NR_nanosleep 240 +-#define TARGET_FREEBSD_NR_ntp_gettime 248 +-#define TARGET_FREEBSD_NR_minherit 250 +-#define TARGET_FREEBSD_NR_rfork 251 +-#define TARGET_FREEBSD_NR_openbsd_poll 252 +-#define TARGET_FREEBSD_NR_issetugid 253 +-#define TARGET_FREEBSD_NR_lchown 254 +-#define TARGET_FREEBSD_NR_aio_read 255 +-#define TARGET_FREEBSD_NR_aio_write 256 +-#define TARGET_FREEBSD_NR_lio_listio 257 +-#define TARGET_FREEBSD_NR_getdents 272 +-#define TARGET_FREEBSD_NR_lchmod 274 +-#define TARGET_FREEBSD_NR_netbsd_lchown 275 +-#define TARGET_FREEBSD_NR_lutimes 276 +-#define TARGET_FREEBSD_NR_netbsd_msync 277 +-#define TARGET_FREEBSD_NR_nstat 278 +-#define TARGET_FREEBSD_NR_nfstat 279 +-#define TARGET_FREEBSD_NR_nlstat 280 +-#define TARGET_FREEBSD_NR_preadv 289 +-#define TARGET_FREEBSD_NR_pwritev 290 +-#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297 +-#define TARGET_FREEBSD_NR_fhopen 298 +-#define TARGET_FREEBSD_NR_fhstat 299 +-#define TARGET_FREEBSD_NR_modnext 300 +-#define TARGET_FREEBSD_NR_modstat 301 +-#define TARGET_FREEBSD_NR_modfnext 302 +-#define TARGET_FREEBSD_NR_modfind 303 +-#define TARGET_FREEBSD_NR_kldload 304 +-#define TARGET_FREEBSD_NR_kldunload 305 +-#define TARGET_FREEBSD_NR_kldfind 306 +-#define TARGET_FREEBSD_NR_kldnext 307 +-#define TARGET_FREEBSD_NR_kldstat 308 +-#define TARGET_FREEBSD_NR_kldfirstmod 309 +-#define TARGET_FREEBSD_NR_getsid 310 +-#define TARGET_FREEBSD_NR_setresuid 311 +-#define TARGET_FREEBSD_NR_setresgid 312 +-#define TARGET_FREEBSD_NR_aio_return 314 +-#define TARGET_FREEBSD_NR_aio_suspend 315 +-#define TARGET_FREEBSD_NR_aio_cancel 316 +-#define TARGET_FREEBSD_NR_aio_error 317 +-#define TARGET_FREEBSD_NR_oaio_read 318 +-#define TARGET_FREEBSD_NR_oaio_write 319 +-#define TARGET_FREEBSD_NR_olio_listio 320 +-#define TARGET_FREEBSD_NR_yield 321 +-#define TARGET_FREEBSD_NR_mlockall 324 +-#define TARGET_FREEBSD_NR_munlockall 325 +-#define TARGET_FREEBSD_NR___getcwd 326 +-#define TARGET_FREEBSD_NR_sched_setparam 327 +-#define TARGET_FREEBSD_NR_sched_getparam 328 +-#define TARGET_FREEBSD_NR_sched_setscheduler 329 +-#define TARGET_FREEBSD_NR_sched_getscheduler 330 +-#define TARGET_FREEBSD_NR_sched_yield 331 +-#define TARGET_FREEBSD_NR_sched_get_priority_max 332 +-#define TARGET_FREEBSD_NR_sched_get_priority_min 333 +-#define TARGET_FREEBSD_NR_sched_rr_get_interval 334 +-#define TARGET_FREEBSD_NR_utrace 335 +-#define TARGET_FREEBSD_NR_freebsd4_sendfile 336 +-#define TARGET_FREEBSD_NR_kldsym 337 +-#define TARGET_FREEBSD_NR_jail 338 +-#define TARGET_FREEBSD_NR_sigprocmask 340 +-#define TARGET_FREEBSD_NR_sigsuspend 341 +-#define TARGET_FREEBSD_NR_freebsd4_sigaction 342 +-#define TARGET_FREEBSD_NR_sigpending 343 +-#define TARGET_FREEBSD_NR_freebsd4_sigreturn 344 +-#define TARGET_FREEBSD_NR_sigtimedwait 345 +-#define TARGET_FREEBSD_NR_sigwaitinfo 346 +-#define TARGET_FREEBSD_NR___acl_get_file 347 +-#define TARGET_FREEBSD_NR___acl_set_file 348 +-#define TARGET_FREEBSD_NR___acl_get_fd 349 +-#define TARGET_FREEBSD_NR___acl_set_fd 350 +-#define TARGET_FREEBSD_NR___acl_delete_file 351 +-#define TARGET_FREEBSD_NR___acl_delete_fd 352 +-#define TARGET_FREEBSD_NR___acl_aclcheck_file 353 +-#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354 +-#define TARGET_FREEBSD_NR_extattrctl 355 +-#define TARGET_FREEBSD_NR_extattr_set_file 356 +-#define TARGET_FREEBSD_NR_extattr_get_file 357 +-#define TARGET_FREEBSD_NR_extattr_delete_file 358 +-#define TARGET_FREEBSD_NR_aio_waitcomplete 359 +-#define TARGET_FREEBSD_NR_getresuid 360 +-#define TARGET_FREEBSD_NR_getresgid 361 +-#define TARGET_FREEBSD_NR_kqueue 362 +-#define TARGET_FREEBSD_NR_kevent 363 +-#define TARGET_FREEBSD_NR_extattr_set_fd 371 +-#define TARGET_FREEBSD_NR_extattr_get_fd 372 +-#define TARGET_FREEBSD_NR_extattr_delete_fd 373 +-#define TARGET_FREEBSD_NR___setugid 374 +-#define TARGET_FREEBSD_NR_nfsclnt 375 +-#define TARGET_FREEBSD_NR_eaccess 376 +-#define TARGET_FREEBSD_NR_nmount 378 +-#define TARGET_FREEBSD_NR___mac_get_proc 384 +-#define TARGET_FREEBSD_NR___mac_set_proc 385 +-#define TARGET_FREEBSD_NR___mac_get_fd 386 +-#define TARGET_FREEBSD_NR___mac_get_file 387 +-#define TARGET_FREEBSD_NR___mac_set_fd 388 +-#define TARGET_FREEBSD_NR___mac_set_file 389 +-#define TARGET_FREEBSD_NR_kenv 390 +-#define TARGET_FREEBSD_NR_lchflags 391 +-#define TARGET_FREEBSD_NR_uuidgen 392 +-#define TARGET_FREEBSD_NR_sendfile 393 +-#define TARGET_FREEBSD_NR_mac_syscall 394 +-#define TARGET_FREEBSD_NR_getfsstat 395 +-#define TARGET_FREEBSD_NR_statfs 396 +-#define TARGET_FREEBSD_NR_fstatfs 397 +-#define TARGET_FREEBSD_NR_fhstatfs 398 +-#define TARGET_FREEBSD_NR_ksem_close 400 +-#define TARGET_FREEBSD_NR_ksem_post 401 +-#define TARGET_FREEBSD_NR_ksem_wait 402 +-#define TARGET_FREEBSD_NR_ksem_trywait 403 +-#define TARGET_FREEBSD_NR_ksem_init 404 +-#define TARGET_FREEBSD_NR_ksem_open 405 +-#define TARGET_FREEBSD_NR_ksem_unlink 406 +-#define TARGET_FREEBSD_NR_ksem_getvalue 407 +-#define TARGET_FREEBSD_NR_ksem_destroy 408 +-#define TARGET_FREEBSD_NR___mac_get_pid 409 +-#define TARGET_FREEBSD_NR___mac_get_link 410 +-#define TARGET_FREEBSD_NR___mac_set_link 411 +-#define TARGET_FREEBSD_NR_extattr_set_link 412 +-#define TARGET_FREEBSD_NR_extattr_get_link 413 +-#define TARGET_FREEBSD_NR_extattr_delete_link 414 +-#define TARGET_FREEBSD_NR___mac_execve 415 +-#define TARGET_FREEBSD_NR_sigaction 416 +-#define TARGET_FREEBSD_NR_sigreturn 417 +-#define TARGET_FREEBSD_NR_getcontext 421 +-#define TARGET_FREEBSD_NR_setcontext 422 +-#define TARGET_FREEBSD_NR_swapcontext 423 +-#define TARGET_FREEBSD_NR_swapoff 424 +-#define TARGET_FREEBSD_NR___acl_get_link 425 +-#define TARGET_FREEBSD_NR___acl_set_link 426 +-#define TARGET_FREEBSD_NR___acl_delete_link 427 +-#define TARGET_FREEBSD_NR___acl_aclcheck_link 428 +-#define TARGET_FREEBSD_NR_sigwait 429 +-#define TARGET_FREEBSD_NR_thr_create 430 +-#define TARGET_FREEBSD_NR_thr_exit 431 +-#define TARGET_FREEBSD_NR_thr_self 432 +-#define TARGET_FREEBSD_NR_thr_kill 433 +-#define TARGET_FREEBSD_NR__umtx_lock 434 +-#define TARGET_FREEBSD_NR__umtx_unlock 435 +-#define TARGET_FREEBSD_NR_jail_attach 436 +-#define TARGET_FREEBSD_NR_extattr_list_fd 437 +-#define TARGET_FREEBSD_NR_extattr_list_file 438 +-#define TARGET_FREEBSD_NR_extattr_list_link 439 +-#define TARGET_FREEBSD_NR_ksem_timedwait 441 +-#define TARGET_FREEBSD_NR_thr_suspend 442 +-#define TARGET_FREEBSD_NR_thr_wake 443 +-#define TARGET_FREEBSD_NR_kldunloadf 444 +-#define TARGET_FREEBSD_NR_audit 445 +-#define TARGET_FREEBSD_NR_auditon 446 +-#define TARGET_FREEBSD_NR_getauid 447 +-#define TARGET_FREEBSD_NR_setauid 448 +-#define TARGET_FREEBSD_NR_getaudit 449 +-#define TARGET_FREEBSD_NR_setaudit 450 +-#define TARGET_FREEBSD_NR_getaudit_addr 451 +-#define TARGET_FREEBSD_NR_setaudit_addr 452 +-#define TARGET_FREEBSD_NR_auditctl 453 +-#define TARGET_FREEBSD_NR__umtx_op 454 +-#define TARGET_FREEBSD_NR_thr_new 455 +-#define TARGET_FREEBSD_NR_sigqueue 456 +-#define TARGET_FREEBSD_NR_kmq_open 457 +-#define TARGET_FREEBSD_NR_kmq_setattr 458 +-#define TARGET_FREEBSD_NR_kmq_timedreceive 459 +-#define TARGET_FREEBSD_NR_kmq_timedsend 460 +-#define TARGET_FREEBSD_NR_kmq_notify 461 +-#define TARGET_FREEBSD_NR_kmq_unlink 462 +-#define TARGET_FREEBSD_NR_abort2 463 +-#define TARGET_FREEBSD_NR_thr_set_name 464 +-#define TARGET_FREEBSD_NR_aio_fsync 465 +-#define TARGET_FREEBSD_NR_rtprio_thread 466 +-#define TARGET_FREEBSD_NR_sctp_peeloff 471 +-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg 472 +-#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov 473 +-#define TARGET_FREEBSD_NR_sctp_generic_recvmsg 474 +-#define TARGET_FREEBSD_NR_pread 475 +-#define TARGET_FREEBSD_NR_pwrite 476 +-#define TARGET_FREEBSD_NR_mmap 477 +-#define TARGET_FREEBSD_NR_lseek 478 +-#define TARGET_FREEBSD_NR_truncate 479 +-#define TARGET_FREEBSD_NR_ftruncate 480 +-#define TARGET_FREEBSD_NR_thr_kill2 481 +-#define TARGET_FREEBSD_NR_shm_open 482 +-#define TARGET_FREEBSD_NR_shm_unlink 483 +-#define TARGET_FREEBSD_NR_cpuset 484 +-#define TARGET_FREEBSD_NR_cpuset_setid 485 +-#define TARGET_FREEBSD_NR_cpuset_getid 486 +-#define TARGET_FREEBSD_NR_cpuset_getaffinity 487 +-#define TARGET_FREEBSD_NR_cpuset_setaffinity 488 +-#define TARGET_FREEBSD_NR_faccessat 489 +-#define TARGET_FREEBSD_NR_fchmodat 490 +-#define TARGET_FREEBSD_NR_fchownat 491 +-#define TARGET_FREEBSD_NR_fexecve 492 +-#define TARGET_FREEBSD_NR_fstatat 493 +-#define TARGET_FREEBSD_NR_futimesat 494 +-#define TARGET_FREEBSD_NR_linkat 495 +-#define TARGET_FREEBSD_NR_mkdirat 496 +-#define TARGET_FREEBSD_NR_mkfifoat 497 +-#define TARGET_FREEBSD_NR_mknodat 498 +-#define TARGET_FREEBSD_NR_openat 499 +-#define TARGET_FREEBSD_NR_readlinkat 500 +-#define TARGET_FREEBSD_NR_renameat 501 +-#define TARGET_FREEBSD_NR_symlinkat 502 +-#define TARGET_FREEBSD_NR_unlinkat 503 +-#define TARGET_FREEBSD_NR_posix_openpt 504 ++#define TARGET_FREEBSD_NR_syscall 0 ++#define TARGET_FREEBSD_NR_exit 1 ++#define TARGET_FREEBSD_NR_fork 2 ++#define TARGET_FREEBSD_NR_read 3 ++#define TARGET_FREEBSD_NR_write 4 ++#define TARGET_FREEBSD_NR_open 5 ++#define TARGET_FREEBSD_NR_close 6 ++#define TARGET_FREEBSD_NR_wait4 7 ++ /* 8 is old creat */ ++#define TARGET_FREEBSD_NR_link 9 ++#define TARGET_FREEBSD_NR_unlink 10 ++ /* 11 is obsolete execv */ ++#define TARGET_FREEBSD_NR_chdir 12 ++#define TARGET_FREEBSD_NR_fchdir 13 ++#define TARGET_FREEBSD_NR_mknod 14 ++#define TARGET_FREEBSD_NR_chmod 15 ++#define TARGET_FREEBSD_NR_chown 16 ++#define TARGET_FREEBSD_NR_break 17 ++#define TARGET_FREEBSD_NR_freebsd4_getfsstat 18 ++ /* 19 is old lseek */ ++#define TARGET_FREEBSD_NR_getpid 20 ++#define TARGET_FREEBSD_NR_mount 21 ++#define TARGET_FREEBSD_NR_unmount 22 ++#define TARGET_FREEBSD_NR_setuid 23 ++#define TARGET_FREEBSD_NR_getuid 24 ++#define TARGET_FREEBSD_NR_geteuid 25 ++#define TARGET_FREEBSD_NR_ptrace 26 ++#define TARGET_FREEBSD_NR_recvmsg 27 ++#define TARGET_FREEBSD_NR_sendmsg 28 ++#define TARGET_FREEBSD_NR_recvfrom 29 ++#define TARGET_FREEBSD_NR_accept 30 ++#define TARGET_FREEBSD_NR_getpeername 31 ++#define TARGET_FREEBSD_NR_getsockname 32 ++#define TARGET_FREEBSD_NR_access 33 ++#define TARGET_FREEBSD_NR_chflags 34 ++#define TARGET_FREEBSD_NR_fchflags 35 ++#define TARGET_FREEBSD_NR_sync 36 ++#define TARGET_FREEBSD_NR_kill 37 ++ /* 38 is old stat */ ++#define TARGET_FREEBSD_NR_getppid 39 ++ /* 40 is old lstat */ ++#define TARGET_FREEBSD_NR_dup 41 ++#define TARGET_FREEBSD_NR_pipe 42 ++#define TARGET_FREEBSD_NR_getegid 43 ++#define TARGET_FREEBSD_NR_profil 44 ++#define TARGET_FREEBSD_NR_ktrace 45 ++ /* 46 is old sigaction */ ++#define TARGET_FREEBSD_NR_getgid 47 ++ /* 48 is old sigprocmask */ ++#define TARGET_FREEBSD_NR_getlogin 49 ++#define TARGET_FREEBSD_NR_setlogin 50 ++#define TARGET_FREEBSD_NR_acct 51 ++ /* 52 is old sigpending */ ++#define TARGET_FREEBSD_NR_sigaltstack 53 ++#define TARGET_FREEBSD_NR_ioctl 54 ++#define TARGET_FREEBSD_NR_reboot 55 ++#define TARGET_FREEBSD_NR_revoke 56 ++#define TARGET_FREEBSD_NR_symlink 57 ++#define TARGET_FREEBSD_NR_readlink 58 ++#define TARGET_FREEBSD_NR_execve 59 ++#define TARGET_FREEBSD_NR_umask 60 ++#define TARGET_FREEBSD_NR_chroot 61 ++ /* 62 is old fstat */ ++ /* 63 is old getkerninfo */ ++ /* 64 is old getpagesize */ ++#define TARGET_FREEBSD_NR_msync 65 ++#define TARGET_FREEBSD_NR_vfork 66 ++ /* 67 is obsolete vread */ ++ /* 68 is obsolete vwrite */ ++#define TARGET_FREEBSD_NR_sbrk 69 ++#define TARGET_FREEBSD_NR_sstk 70 ++ /* 71 is old mmap */ ++#define TARGET_FREEBSD_NR_vadvise 72 ++#define TARGET_FREEBSD_NR_munmap 73 ++#define TARGET_FREEBSD_NR_mprotect 74 ++#define TARGET_FREEBSD_NR_madvise 75 ++ /* 76 is obsolete vhangup */ ++ /* 77 is obsolete vlimit */ ++#define TARGET_FREEBSD_NR_mincore 78 ++#define TARGET_FREEBSD_NR_getgroups 79 ++#define TARGET_FREEBSD_NR_setgroups 80 ++#define TARGET_FREEBSD_NR_getpgrp 81 ++#define TARGET_FREEBSD_NR_setpgid 82 ++#define TARGET_FREEBSD_NR_setitimer 83 ++ /* 84 is old wait */ ++#define TARGET_FREEBSD_NR_swapon 85 ++#define TARGET_FREEBSD_NR_getitimer 86 ++ /* 87 is old gethostname */ ++ /* 88 is old sethostname */ ++#define TARGET_FREEBSD_NR_getdtablesize 89 ++#define TARGET_FREEBSD_NR_dup2 90 ++#define TARGET_FREEBSD_NR_fcntl 92 ++#define TARGET_FREEBSD_NR_select 93 ++#define TARGET_FREEBSD_NR_fsync 95 ++#define TARGET_FREEBSD_NR_setpriority 96 ++#define TARGET_FREEBSD_NR_socket 97 ++#define TARGET_FREEBSD_NR_connect 98 ++ /* 99 is old accept */ ++#define TARGET_FREEBSD_NR_getpriority 100 ++ /* 101 is old send */ ++ /* 102 is old recv */ ++ /* 103 is old sigreturn */ ++#define TARGET_FREEBSD_NR_bind 104 ++#define TARGET_FREEBSD_NR_setsockopt 105 ++#define TARGET_FREEBSD_NR_listen 106 ++ /* 107 is obsolete vtimes */ ++ /* 108 is old sigvec */ ++ /* 109 is old sigblock */ ++ /* 110 is old sigsetmask */ ++ /* 111 is old sigsuspend */ ++ /* 112 is old sigstack */ ++ /* 113 is old recvmsg */ ++ /* 114 is old sendmsg */ ++ /* 115 is obsolete vtrace */ ++#define TARGET_FREEBSD_NR_gettimeofday 116 ++#define TARGET_FREEBSD_NR_getrusage 117 ++#define TARGET_FREEBSD_NR_getsockopt 118 ++#define TARGET_FREEBSD_NR_readv 120 ++#define TARGET_FREEBSD_NR_writev 121 ++#define TARGET_FREEBSD_NR_settimeofday 122 ++#define TARGET_FREEBSD_NR_fchown 123 ++#define TARGET_FREEBSD_NR_fchmod 124 ++ /* 125 is old recvfrom */ ++#define TARGET_FREEBSD_NR_setreuid 126 ++#define TARGET_FREEBSD_NR_setregid 127 ++#define TARGET_FREEBSD_NR_rename 128 ++ /* 129 is old truncate */ ++ /* 130 is old ftruncate */ ++#define TARGET_FREEBSD_NR_flock 131 ++#define TARGET_FREEBSD_NR_mkfifo 132 ++#define TARGET_FREEBSD_NR_sendto 133 ++#define TARGET_FREEBSD_NR_shutdown 134 ++#define TARGET_FREEBSD_NR_socketpair 135 ++#define TARGET_FREEBSD_NR_mkdir 136 ++#define TARGET_FREEBSD_NR_rmdir 137 ++#define TARGET_FREEBSD_NR_utimes 138 ++ /* 139 is obsolete 4.2 sigreturn */ ++#define TARGET_FREEBSD_NR_adjtime 140 ++ /* 141 is old getpeername */ ++ /* 142 is old gethostid */ ++ /* 143 is old sethostid */ ++ /* 144 is old getrlimit */ ++ /* 145 is old setrlimit */ ++ /* 146 is old killpg */ ++#define TARGET_FREEBSD_NR_setsid 147 ++#define TARGET_FREEBSD_NR_quotactl 148 ++ /* 149 is old quota */ ++ /* 150 is old getsockname */ ++#define TARGET_FREEBSD_NR_nlm_syscall 154 ++#define TARGET_FREEBSD_NR_nfssvc 155 ++ /* 156 is old getdirentries */ ++#define TARGET_FREEBSD_NR_freebsd4_statfs 157 ++#define TARGET_FREEBSD_NR_freebsd4_fstatfs 158 ++#define TARGET_FREEBSD_NR_lgetfh 160 ++#define TARGET_FREEBSD_NR_getfh 161 ++#define TARGET_FREEBSD_NR_freebsd4_getdomainname 162 ++#define TARGET_FREEBSD_NR_freebsd4_setdomainname 163 ++#define TARGET_FREEBSD_NR_freebsd4_uname 164 ++#define TARGET_FREEBSD_NR_sysarch 165 ++#define TARGET_FREEBSD_NR_rtprio 166 ++#define TARGET_FREEBSD_NR_semsys 169 ++#define TARGET_FREEBSD_NR_msgsys 170 ++#define TARGET_FREEBSD_NR_shmsys 171 ++#define TARGET_FREEBSD_NR_freebsd6_pread 173 ++#define TARGET_FREEBSD_NR_freebsd6_pwrite 174 ++#define TARGET_FREEBSD_NR_setfib 175 ++#define TARGET_FREEBSD_NR_ntp_adjtime 176 ++#define TARGET_FREEBSD_NR_setgid 181 ++#define TARGET_FREEBSD_NR_setegid 182 ++#define TARGET_FREEBSD_NR_seteuid 183 ++#define TARGET_FREEBSD_NR_stat 188 ++#define TARGET_FREEBSD_NR_fstat 189 ++#define TARGET_FREEBSD_NR_lstat 190 ++#define TARGET_FREEBSD_NR_pathconf 191 ++#define TARGET_FREEBSD_NR_fpathconf 192 ++#define TARGET_FREEBSD_NR_getrlimit 194 ++#define TARGET_FREEBSD_NR_setrlimit 195 ++#define TARGET_FREEBSD_NR_getdirentries 196 ++#define TARGET_FREEBSD_NR_freebsd6_mmap 197 ++#define TARGET_FREEBSD_NR___syscall 198 ++#define TARGET_FREEBSD_NR_freebsd6_lseek 199 ++#define TARGET_FREEBSD_NR_freebsd6_truncate 200 ++#define TARGET_FREEBSD_NR_freebsd6_ftruncate 201 ++#define TARGET_FREEBSD_NR___sysctl 202 ++#define TARGET_FREEBSD_NR_mlock 203 ++#define TARGET_FREEBSD_NR_munlock 204 ++#define TARGET_FREEBSD_NR_undelete 205 ++#define TARGET_FREEBSD_NR_futimes 206 ++#define TARGET_FREEBSD_NR_getpgid 207 ++#define TARGET_FREEBSD_NR_poll 209 ++#define TARGET_FREEBSD_NR_freebsd7___semctl 220 ++#define TARGET_FREEBSD_NR_semget 221 ++#define TARGET_FREEBSD_NR_semop 222 ++#define TARGET_FREEBSD_NR_freebsd7_msgctl 224 ++#define TARGET_FREEBSD_NR_msgget 225 ++#define TARGET_FREEBSD_NR_msgsnd 226 ++#define TARGET_FREEBSD_NR_msgrcv 227 ++#define TARGET_FREEBSD_NR_shmat 228 ++#define TARGET_FREEBSD_NR_freebsd7_shmctl 229 ++#define TARGET_FREEBSD_NR_shmdt 230 ++#define TARGET_FREEBSD_NR_shmget 231 ++#define TARGET_FREEBSD_NR_clock_gettime 232 ++#define TARGET_FREEBSD_NR_clock_settime 233 ++#define TARGET_FREEBSD_NR_clock_getres 234 ++#define TARGET_FREEBSD_NR_ktimer_create 235 ++#define TARGET_FREEBSD_NR_ktimer_delete 236 ++#define TARGET_FREEBSD_NR_ktimer_settime 237 ++#define TARGET_FREEBSD_NR_ktimer_gettime 238 ++#define TARGET_FREEBSD_NR_ktimer_getoverrun 239 ++#define TARGET_FREEBSD_NR_nanosleep 240 ++#define TARGET_FREEBSD_NR_ntp_gettime 248 ++#define TARGET_FREEBSD_NR_minherit 250 ++#define TARGET_FREEBSD_NR_rfork 251 ++#define TARGET_FREEBSD_NR_openbsd_poll 252 ++#define TARGET_FREEBSD_NR_issetugid 253 ++#define TARGET_FREEBSD_NR_lchown 254 ++#define TARGET_FREEBSD_NR_aio_read 255 ++#define TARGET_FREEBSD_NR_aio_write 256 ++#define TARGET_FREEBSD_NR_lio_listio 257 ++#define TARGET_FREEBSD_NR_getdents 272 ++#define TARGET_FREEBSD_NR_lchmod 274 ++#define TARGET_FREEBSD_NR_netbsd_lchown 275 ++#define TARGET_FREEBSD_NR_lutimes 276 ++#define TARGET_FREEBSD_NR_netbsd_msync 277 ++#define TARGET_FREEBSD_NR_nstat 278 ++#define TARGET_FREEBSD_NR_nfstat 279 ++#define TARGET_FREEBSD_NR_nlstat 280 ++#define TARGET_FREEBSD_NR_preadv 289 ++#define TARGET_FREEBSD_NR_pwritev 290 ++#define TARGET_FREEBSD_NR_freebsd4_fhstatfs 297 ++#define TARGET_FREEBSD_NR_fhopen 298 ++#define TARGET_FREEBSD_NR_fhstat 299 ++#define TARGET_FREEBSD_NR_modnext 300 ++#define TARGET_FREEBSD_NR_modstat 301 ++#define TARGET_FREEBSD_NR_modfnext 302 ++#define TARGET_FREEBSD_NR_modfind 303 ++#define TARGET_FREEBSD_NR_kldload 304 ++#define TARGET_FREEBSD_NR_kldunload 305 ++#define TARGET_FREEBSD_NR_kldfind 306 ++#define TARGET_FREEBSD_NR_kldnext 307 ++#define TARGET_FREEBSD_NR_kldstat 308 ++#define TARGET_FREEBSD_NR_kldfirstmod 309 ++#define TARGET_FREEBSD_NR_getsid 310 ++#define TARGET_FREEBSD_NR_setresuid 311 ++#define TARGET_FREEBSD_NR_setresgid 312 ++ /* 313 is obsolete signanosleep */ ++#define TARGET_FREEBSD_NR_aio_return 314 ++#define TARGET_FREEBSD_NR_aio_suspend 315 ++#define TARGET_FREEBSD_NR_aio_cancel 316 ++#define TARGET_FREEBSD_NR_aio_error 317 ++#define TARGET_FREEBSD_NR_oaio_read 318 ++#define TARGET_FREEBSD_NR_oaio_write 319 ++#define TARGET_FREEBSD_NR_olio_listio 320 ++#define TARGET_FREEBSD_NR_yield 321 ++ /* 322 is obsolete thr_sleep */ ++ /* 323 is obsolete thr_wakeup */ ++#define TARGET_FREEBSD_NR_mlockall 324 ++#define TARGET_FREEBSD_NR_munlockall 325 ++#define TARGET_FREEBSD_NR___getcwd 326 ++#define TARGET_FREEBSD_NR_sched_setparam 327 ++#define TARGET_FREEBSD_NR_sched_getparam 328 ++#define TARGET_FREEBSD_NR_sched_setscheduler 329 ++#define TARGET_FREEBSD_NR_sched_getscheduler 330 ++#define TARGET_FREEBSD_NR_sched_yield 331 ++#define TARGET_FREEBSD_NR_sched_get_priority_max 332 ++#define TARGET_FREEBSD_NR_sched_get_priority_min 333 ++#define TARGET_FREEBSD_NR_sched_rr_get_interval 334 ++#define TARGET_FREEBSD_NR_utrace 335 ++#define TARGET_FREEBSD_NR_freebsd4_sendfile 336 ++#define TARGET_FREEBSD_NR_kldsym 337 ++#define TARGET_FREEBSD_NR_jail 338 ++#define TARGET_FREEBSD_NR_nnpfs_syscall 339 ++#define TARGET_FREEBSD_NR_sigprocmask 340 ++#define TARGET_FREEBSD_NR_sigsuspend 341 ++#define TARGET_FREEBSD_NR_freebsd4_sigaction 342 ++#define TARGET_FREEBSD_NR_sigpending 343 ++#define TARGET_FREEBSD_NR_freebsd4_sigreturn 344 ++#define TARGET_FREEBSD_NR_sigtimedwait 345 ++#define TARGET_FREEBSD_NR_sigwaitinfo 346 ++#define TARGET_FREEBSD_NR___acl_get_file 347 ++#define TARGET_FREEBSD_NR___acl_set_file 348 ++#define TARGET_FREEBSD_NR___acl_get_fd 349 ++#define TARGET_FREEBSD_NR___acl_set_fd 350 ++#define TARGET_FREEBSD_NR___acl_delete_file 351 ++#define TARGET_FREEBSD_NR___acl_delete_fd 352 ++#define TARGET_FREEBSD_NR___acl_aclcheck_file 353 ++#define TARGET_FREEBSD_NR___acl_aclcheck_fd 354 ++#define TARGET_FREEBSD_NR_extattrctl 355 ++#define TARGET_FREEBSD_NR_extattr_set_file 356 ++#define TARGET_FREEBSD_NR_extattr_get_file 357 ++#define TARGET_FREEBSD_NR_extattr_delete_file 358 ++#define TARGET_FREEBSD_NR_aio_waitcomplete 359 ++#define TARGET_FREEBSD_NR_getresuid 360 ++#define TARGET_FREEBSD_NR_getresgid 361 ++#define TARGET_FREEBSD_NR_kqueue 362 ++#define TARGET_FREEBSD_NR_kevent 363 ++#define TARGET_FREEBSD_NR_extattr_set_fd 371 ++#define TARGET_FREEBSD_NR_extattr_get_fd 372 ++#define TARGET_FREEBSD_NR_extattr_delete_fd 373 ++#define TARGET_FREEBSD_NR___setugid 374 ++#define TARGET_FREEBSD_NR_eaccess 376 ++#define TARGET_FREEBSD_NR_afs3_syscall 377 ++#define TARGET_FREEBSD_NR_nmount 378 ++#define TARGET_FREEBSD_NR___mac_get_proc 384 ++#define TARGET_FREEBSD_NR___mac_set_proc 385 ++#define TARGET_FREEBSD_NR___mac_get_fd 386 ++#define TARGET_FREEBSD_NR___mac_get_file 387 ++#define TARGET_FREEBSD_NR___mac_set_fd 388 ++#define TARGET_FREEBSD_NR___mac_set_file 389 ++#define TARGET_FREEBSD_NR_kenv 390 ++#define TARGET_FREEBSD_NR_lchflags 391 ++#define TARGET_FREEBSD_NR_uuidgen 392 ++#define TARGET_FREEBSD_NR_sendfile 393 ++#define TARGET_FREEBSD_NR_mac_syscall 394 ++#define TARGET_FREEBSD_NR_getfsstat 395 ++#define TARGET_FREEBSD_NR_statfs 396 ++#define TARGET_FREEBSD_NR_fstatfs 397 ++#define TARGET_FREEBSD_NR_fhstatfs 398 ++#define TARGET_FREEBSD_NR_ksem_close 400 ++#define TARGET_FREEBSD_NR_ksem_post 401 ++#define TARGET_FREEBSD_NR_ksem_wait 402 ++#define TARGET_FREEBSD_NR_ksem_trywait 403 ++#define TARGET_FREEBSD_NR_ksem_init 404 ++#define TARGET_FREEBSD_NR_ksem_open 405 ++#define TARGET_FREEBSD_NR_ksem_unlink 406 ++#define TARGET_FREEBSD_NR_ksem_getvalue 407 ++#define TARGET_FREEBSD_NR_ksem_destroy 408 ++#define TARGET_FREEBSD_NR___mac_get_pid 409 ++#define TARGET_FREEBSD_NR___mac_get_link 410 ++#define TARGET_FREEBSD_NR___mac_set_link 411 ++#define TARGET_FREEBSD_NR_extattr_set_link 412 ++#define TARGET_FREEBSD_NR_extattr_get_link 413 ++#define TARGET_FREEBSD_NR_extattr_delete_link 414 ++#define TARGET_FREEBSD_NR___mac_execve 415 ++#define TARGET_FREEBSD_NR_sigaction 416 ++#define TARGET_FREEBSD_NR_sigreturn 417 ++#define TARGET_FREEBSD_NR_getcontext 421 ++#define TARGET_FREEBSD_NR_setcontext 422 ++#define TARGET_FREEBSD_NR_swapcontext 423 ++#define TARGET_FREEBSD_NR_swapoff 424 ++#define TARGET_FREEBSD_NR___acl_get_link 425 ++#define TARGET_FREEBSD_NR___acl_set_link 426 ++#define TARGET_FREEBSD_NR___acl_delete_link 427 ++#define TARGET_FREEBSD_NR___acl_aclcheck_link 428 ++#define TARGET_FREEBSD_NR_sigwait 429 ++#define TARGET_FREEBSD_NR_thr_create 430 ++#define TARGET_FREEBSD_NR_thr_exit 431 ++#define TARGET_FREEBSD_NR_thr_self 432 ++#define TARGET_FREEBSD_NR_thr_kill 433 ++#define TARGET_FREEBSD_NR__umtx_lock 434 ++#define TARGET_FREEBSD_NR__umtx_unlock 435 ++#define TARGET_FREEBSD_NR_jail_attach 436 ++#define TARGET_FREEBSD_NR_extattr_list_fd 437 ++#define TARGET_FREEBSD_NR_extattr_list_file 438 ++#define TARGET_FREEBSD_NR_extattr_list_link 439 ++#define TARGET_FREEBSD_NR_ksem_timedwait 441 ++#define TARGET_FREEBSD_NR_thr_suspend 442 ++#define TARGET_FREEBSD_NR_thr_wake 443 ++#define TARGET_FREEBSD_NR_kldunloadf 444 ++#define TARGET_FREEBSD_NR_audit 445 ++#define TARGET_FREEBSD_NR_auditon 446 ++#define TARGET_FREEBSD_NR_getauid 447 ++#define TARGET_FREEBSD_NR_setauid 448 ++#define TARGET_FREEBSD_NR_getaudit 449 ++#define TARGET_FREEBSD_NR_setaudit 450 ++#define TARGET_FREEBSD_NR_getaudit_addr 451 ++#define TARGET_FREEBSD_NR_setaudit_addr 452 ++#define TARGET_FREEBSD_NR_auditctl 453 ++#define TARGET_FREEBSD_NR__umtx_op 454 ++#define TARGET_FREEBSD_NR_thr_new 455 ++#define TARGET_FREEBSD_NR_sigqueue 456 ++#define TARGET_FREEBSD_NR_kmq_open 457 ++#define TARGET_FREEBSD_NR_kmq_setattr 458 ++#define TARGET_FREEBSD_NR_kmq_timedreceive 459 ++#define TARGET_FREEBSD_NR_kmq_timedsend 460 ++#define TARGET_FREEBSD_NR_kmq_notify 461 ++#define TARGET_FREEBSD_NR_kmq_unlink 462 ++#define TARGET_FREEBSD_NR_abort2 463 ++#define TARGET_FREEBSD_NR_thr_set_name 464 ++#define TARGET_FREEBSD_NR_aio_fsync 465 ++#define TARGET_FREEBSD_NR_rtprio_thread 466 ++#define TARGET_FREEBSD_NR_sctp_peeloff 471 ++#define TARGET_FREEBSD_NR_sctp_generic_sendmsg 472 ++#define TARGET_FREEBSD_NR_sctp_generic_sendmsg_iov 473 ++#define TARGET_FREEBSD_NR_sctp_generic_recvmsg 474 ++#define TARGET_FREEBSD_NR_pread 475 ++#define TARGET_FREEBSD_NR_pwrite 476 ++#define TARGET_FREEBSD_NR_mmap 477 ++#define TARGET_FREEBSD_NR_lseek 478 ++#define TARGET_FREEBSD_NR_truncate 479 ++#define TARGET_FREEBSD_NR_ftruncate 480 ++#define TARGET_FREEBSD_NR_thr_kill2 481 ++#define TARGET_FREEBSD_NR_shm_open 482 ++#define TARGET_FREEBSD_NR_shm_unlink 483 ++#define TARGET_FREEBSD_NR_cpuset 484 ++#define TARGET_FREEBSD_NR_cpuset_setid 485 ++#define TARGET_FREEBSD_NR_cpuset_getid 486 ++#define TARGET_FREEBSD_NR_cpuset_getaffinity 487 ++#define TARGET_FREEBSD_NR_cpuset_setaffinity 488 ++#define TARGET_FREEBSD_NR_faccessat 489 ++#define TARGET_FREEBSD_NR_fchmodat 490 ++#define TARGET_FREEBSD_NR_fchownat 491 ++#define TARGET_FREEBSD_NR_fexecve 492 ++#define TARGET_FREEBSD_NR_fstatat 493 ++#define TARGET_FREEBSD_NR_futimesat 494 ++#define TARGET_FREEBSD_NR_linkat 495 ++#define TARGET_FREEBSD_NR_mkdirat 496 ++#define TARGET_FREEBSD_NR_mkfifoat 497 ++#define TARGET_FREEBSD_NR_mknodat 498 ++#define TARGET_FREEBSD_NR_openat 499 ++#define TARGET_FREEBSD_NR_readlinkat 500 ++#define TARGET_FREEBSD_NR_renameat 501 ++#define TARGET_FREEBSD_NR_symlinkat 502 ++#define TARGET_FREEBSD_NR_unlinkat 503 ++#define TARGET_FREEBSD_NR_posix_openpt 504 ++#define TARGET_FREEBSD_NR_gssd_syscall 505 ++#define TARGET_FREEBSD_NR_jail_get 506 ++#define TARGET_FREEBSD_NR_jail_set 507 ++#define TARGET_FREEBSD_NR_jail_remove 508 ++#define TARGET_FREEBSD_NR_closefrom 509 ++#define TARGET_FREEBSD_NR___semctl 510 ++#define TARGET_FREEBSD_NR_msgctl 511 ++#define TARGET_FREEBSD_NR_shmctl 512 ++#define TARGET_FREEBSD_NR_lpathconf 513 ++#define TARGET_FREEBSD_NR_cap_new 514 ++#define TARGET_FREEBSD_NR_cap_getrights 515 ++#define TARGET_FREEBSD_NR_cap_enter 516 ++#define TARGET_FREEBSD_NR_cap_getmode 517 ++#define TARGET_FREEBSD_NR_pdfork 518 ++#define TARGET_FREEBSD_NR_pdkill 519 ++#define TARGET_FREEBSD_NR_pdgetpid 520 ++#define TARGET_FREEBSD_NR_pselect 522 ++#define TARGET_FREEBSD_NR_getloginclass 523 ++#define TARGET_FREEBSD_NR_setloginclass 524 ++#define TARGET_FREEBSD_NR_rctl_get_racct 525 ++#define TARGET_FREEBSD_NR_rctl_get_rules 526 ++#define TARGET_FREEBSD_NR_rctl_get_limits 527 ++#define TARGET_FREEBSD_NR_rctl_add_rule 528 ++#define TARGET_FREEBSD_NR_rctl_remove_rule 529 ++#define TARGET_FREEBSD_NR_posix_fallocate 530 ++#define TARGET_FREEBSD_NR_posix_fadvise 531 ++#define TARGET_FREEBSD_NR_MAXSYSCALL 532 +diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h +index 2ef36d1..285e7f9 100644 +--- a/bsd-user/i386/target_signal.h ++++ b/bsd-user/i386/target_signal.h +@@ -3,18 +3,12 @@ + + #include "cpu.h" + +-/* this struct defines a stack used during syscall handling */ +- +-typedef struct target_sigaltstack { +- abi_ulong ss_sp; +- abi_long ss_flags; +- abi_ulong ss_size; +-} target_stack_t; +- +- + static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) + { + return state->regs[R_ESP]; + } + ++#define TARGET_MINSIGSTKSZ (512 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/i386/target_vmparam.h b/bsd-user/i386/target_vmparam.h +new file mode 100644 +index 0000000..8fc98d5 +--- /dev/null ++++ b/bsd-user/i386/target_vmparam.h +@@ -0,0 +1,27 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#if defined(__FreeBSD__) ++ ++#define TARGET_USRSTACK (0xbfc00000) ++ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#define TARGET_SZSIGCODE 0 ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++#endif ++ ++#endif /* _TARGET_VMPARAM_H_ */ +diff --git a/bsd-user/main.c b/bsd-user/main.c +index b4e42f3..146f022 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -642,6 +642,243 @@ void cpu_loop(CPUARMState *env) + + #endif + ++#if defined(TARGET_MIPS) || defined(TARGET_MIPS64) ++ ++/* ++ * From sys/mips/mips/trap.c syscalls have the following stored away in the ++ * registers: ++ * ++ * v0(2): if either SYS___syscall (198) or SYS_syscall (0) then indirect syscall ++ * otherwise it is a direct syscall. ++ * ++ * If direct syscall: ++ * ++ * MIPS MIPS64 ++ * v0(2): v0(2) syscall # ++ * a0(4): a0(4) arg0 ++ * a1(5): a1(5) arg1 ++ * a2(6): a2(6) arg2 ++ * a3(7): a3(7) arg3 ++ * t4(12): a4(8) arg4 ++ * t5(13): a5(9) arg5 ++ * t6(14): a6(10) arg6 ++ * t7(15): a7(11) arg7 ++ * ++ * If indirect syscall: ++ * ++ * MIPS MIPS64 ++ * a0(4): a0(4) syscall # ++ * a1(5): a1(5) arg0 ++ * a2(6): a2(6) arg1 ++ * a3(7): a3(7) arg2 ++ * t4(12): a4(8) arg3 ++ * t5(13): a5(9) arg4 ++ * t6(14): a6(10) arg5 ++ * t7(15): a7(11) arg6 ++ * ++ */ ++ ++#include /* For SYS_[__]syscall, SYS_MAXSYSCALL */ ++ ++static int do_store_exclusive(CPUMIPSState *env) ++{ ++ target_ulong addr; ++ target_ulong page_addr; ++ target_ulong val; ++ int flags; ++ int segv = 0; ++ int reg; ++ int d; ++ ++ addr = env->lladdr; ++ page_addr = addr & TARGET_PAGE_MASK; ++ start_exclusive(); ++ mmap_lock(); ++ flags = page_get_flags(page_addr); ++ if ((flags & PAGE_READ) == 0) { ++ segv = 1; ++ } else { ++ reg = env->llreg & 0x1f; ++ d = (env->llreg & 0x20) != 0; ++ if (d) { ++ segv = get_user_s64(val, addr); ++ } else { ++ segv = get_user_s32(val, addr); ++ } ++ if (!segv) { ++ if (val != env->llval) { ++ env->active_tc.gpr[reg] = 0; ++ } else { ++ if (d) { ++ segv = ++ put_user_u64(env->llnewval, addr); ++ } else { ++ segv = ++ put_user_u32(env->llnewval, addr); ++ } ++ if (!segv) { ++ env->active_tc.gpr[reg] = 1; ++ } ++ } ++ } ++ } ++ env->lladdr = -1; ++ if (!segv) { ++ env->active_tc.PC += 4; ++ } ++ mmap_unlock(); ++ end_exclusive(); ++ return (segv); ++} ++ ++void cpu_loop(CPUMIPSState *env) ++{ ++ target_siginfo_t info; ++ int trapnr; ++ abi_long ret; ++ unsigned int syscall_num; ++ ++ for(;;) { ++ cpu_exec_start(env); ++ trapnr = cpu_mips_exec(env); ++ cpu_exec_end(env); ++ switch(trapnr) { ++ case EXCP_SYSCALL: /* syscall exception */ ++ syscall_num = env->active_tc.gpr[2]; /* v0 */ ++ env->active_tc.PC += 4; ++ if (syscall_num >= SYS_MAXSYSCALL) { ++ ret = -TARGET_ENOSYS; ++ } else { ++ if (SYS_syscall == syscall_num || ++ SYS___syscall == syscall_num) { ++#if defined(TARGET_MIPS64) ++ ret = do_freebsd_syscall(env, ++ env->active_tc.gpr[4],/* syscall #*/ ++ env->active_tc.gpr[5], /* arg0 */ ++ env->active_tc.gpr[6], /* arg1 */ ++ env->active_tc.gpr[7], /* arg2 */ ++ env->active_tc.gpr[8], /* arg3 */ ++ env->active_tc.gpr[9], /* arg4 */ ++ env->active_tc.gpr[10],/* arg5 */ ++ env->active_tc.gpr[11],/* arg6 */ ++ 0 /* no arg 7 */); ++ } else { ++ ret = do_freebsd_syscall(env, ++ syscall_num, ++ env->active_tc.gpr[4], ++ env->active_tc.gpr[5], ++ env->active_tc.gpr[6], ++ env->active_tc.gpr[7], ++ env->active_tc.gpr[8], ++ env->active_tc.gpr[9], ++ env->active_tc.gpr[10], ++ env->active_tc.gpr[11] ++ ); ++ ++#else /* ! TARGET_MIPS64 */ ++ /* indirect syscall */ ++ ret = do_freebsd_syscall(env, ++ env->active_tc.gpr[4],/* syscall #*/ ++ env->active_tc.gpr[5], /* a1/arg0 */ ++ env->active_tc.gpr[6], /* a2/arg1 */ ++ env->active_tc.gpr[7], /* a3/arg2 */ ++ env->active_tc.gpr[12],/* t4/arg3 */ ++ env->active_tc.gpr[13],/* t5/arg4 */ ++ env->active_tc.gpr[14],/* t6/arg5 */ ++ env->active_tc.gpr[15],/* t7/arg6 */ ++ 0 /* no arg7 */ ); ++ } else { ++ /* direct syscall */ ++ ret = do_freebsd_syscall(env, ++ syscall_num, ++ env->active_tc.gpr[4], /* a0/arg0 */ ++ env->active_tc.gpr[5], /* a1/arg1 */ ++ env->active_tc.gpr[6], /* a2/arg2 */ ++ env->active_tc.gpr[7], /* a3/arg3 */ ++ env->active_tc.gpr[12],/* t4/arg4 */ ++ env->active_tc.gpr[13],/* t5/arg5 */ ++ env->active_tc.gpr[14],/* t6/arg6 */ ++ env->active_tc.gpr[15] /* t7/arg7 */ ++ ); ++#endif /* ! TARGET_MIPS64 */ ++ } ++ } ++/* done_syscall: */ ++ if (-TARGET_QEMU_ESIGRETURN == ret) { ++ /* ++ * Returning from a successful sigreturn ++ * syscall. Avoid clobbering register state. ++ */ ++ break; ++ } ++ if ((unsigned int)ret >= (unsigned int)(-1133)) { ++ env->active_tc.gpr[7] = 1; ++ ret = -ret; ++ } else { ++ env->active_tc.gpr[7] = 0; ++ } ++ env->active_tc.gpr[2] = ret; /* v0 <- ret */ ++ break; ++ ++ case EXCP_TLBL: /* TLB miss on load */ ++ case EXCP_TLBS: /* TLB miss on store */ ++ case EXCP_AdEL: /* bad address on load */ ++ case EXCP_AdES: /* bad address on store */ ++ info.si_signo = TARGET_SIGSEGV; ++ info.si_errno = 0; ++ /* XXX: check env->error_code */ ++ info.si_code = TARGET_SEGV_MAPERR; ++ info.si_addr = env->CP0_BadVAddr; ++ queue_signal(env, info.si_signo, &info); ++ break; ++ ++ case EXCP_CpU: /* coprocessor unusable */ ++ case EXCP_RI: /* reserved instruction */ ++ info.si_signo = TARGET_SIGILL; ++ info.si_errno = 0; ++ info.si_code = 0; ++ queue_signal(env, info.si_signo, &info); ++ break; ++ ++ case EXCP_INTERRUPT: /* async interrupt */ ++ /* just indicate that signals should be handled asap */ ++ break; ++ ++ case EXCP_DEBUG: /* cpu stopped after a breakpoint */ ++ { ++ int sig; ++ ++ sig = gdb_handlesig(env, TARGET_SIGTRAP); ++ if (sig) { ++ info.si_signo = sig; ++ info.si_errno = 0; ++ info.si_code = TARGET_TRAP_BRKPT; ++ queue_signal(env, info.si_signo, &info); ++ } ++ } ++ break; ++ ++ case EXCP_SC: ++ if (do_store_exclusive(env)) { ++ info.si_signo = TARGET_SIGSEGV; ++ info.si_errno = 0; ++ info.si_code = TARGET_SEGV_MAPERR; ++ info.si_addr = env->active_tc.PC; ++ queue_signal(env, info.si_signo, &info); ++ } ++ break; ++ ++ default: ++ fprintf(stderr, "qemu: unhandled CPU exception " ++ "0x%x - aborting\n", trapnr); ++ cpu_dump_state(env, stderr, fprintf, 0); ++ abort(); ++ } ++ process_pending_signals(env); ++ } ++} ++#endif /* defined(TARGET_MIPS) */ ++ + #ifdef TARGET_SPARC + #define SPARC64_STACK_BIAS 2047 + +@@ -969,6 +1206,15 @@ static void usage(void) + + THREAD CPUArchState *thread_env; + ++void stop_all_tasks(void) ++{ ++ /* ++ * We trust when using NPTL (pthreads) start_exclusive() handles thread ++ * stopping correctly. ++ */ ++ start_exclusive(); ++} ++ + /* Assumes contents are already zeroed. */ + void init_task_state(TaskState *ts) + { +@@ -990,6 +1236,7 @@ int main(int argc, char **argv) + const char *log_mask = NULL; + struct target_pt_regs regs1, *regs = ®s1; + struct image_info info1, *info = &info1; ++ struct bsd_binprm bprm; + TaskState ts1, *ts = &ts1; + CPUArchState *env; + int optind; +@@ -997,7 +1244,11 @@ int main(int argc, char **argv) + int gdbstub_port = 0; + char **target_environ, **wrk; + envlist_t *envlist = NULL; ++#ifdef __FreeBSD__ ++ bsd_type = target_freebsd; ++#else + bsd_type = target_openbsd; ++#endif + + if (argc <= 1) + usage(); +@@ -1141,6 +1392,8 @@ int main(int argc, char **argv) + /* Zero out image_info */ + memset(info, 0, sizeof(struct image_info)); + ++ memset(&bprm, 0, sizeof(bprm)); ++ + /* Scan interp_prefix dir for replacement files. */ + init_paths(interp_prefix); + +@@ -1151,6 +1404,12 @@ int main(int argc, char **argv) + #else + cpu_model = "qemu32"; + #endif ++#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64) ++#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) ++ cpu_model = "20Kc"; ++#else ++ cpu_model = "24Kf"; ++#endif + #elif defined(TARGET_SPARC) + #ifdef TARGET_SPARC64 + cpu_model = "TI UltraSparc II"; +@@ -1211,7 +1470,8 @@ int main(int argc, char **argv) + } + #endif /* CONFIG_USE_GUEST_BASE */ + +- if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { ++ if (loader_exec(filename, argv+optind, target_environ, regs, info, ++ &bprm)!= 0) { + printf("Error loading %s\n", filename); + _exit(1); + } +@@ -1256,6 +1516,7 @@ int main(int argc, char **argv) + memset(ts, 0, sizeof(TaskState)); + init_task_state(ts); + ts->info = info; ++ ts->bprm = &bprm; + env->opaque = ts; + + #if defined(TARGET_I386) +@@ -1394,6 +1655,20 @@ int main(int argc, char **argv) + env->regs[i] = regs->uregs[i]; + } + } ++#elif defined(TARGET_MIPS) ++ { ++ int i; ++ for(i = 0; i < 32; i++) { ++ env->active_tc.gpr[i] = regs->regs[i]; ++ } ++ env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1; ++ if (regs->cp0_epc & 1) { ++ env->hflags |= MIPS_HFLAG_M16; ++ } ++#if defined(TARGET_MIPS64) ++ env->hflags |= MIPS_HFLAG_UX; ++#endif ++ } + #else + #error unsupported target CPU + #endif +diff --git a/bsd-user/mips/syscall.h b/bsd-user/mips/syscall.h +new file mode 100644 +index 0000000..8923556 +--- /dev/null ++++ b/bsd-user/mips/syscall.h +@@ -0,0 +1,21 @@ ++ ++/* this struct defines the way the registers are stored on the ++ stack during a system call. */ ++ ++struct target_pt_regs { ++ /* Pad bytes for argument save space on the stack. */ ++ abi_ulong pad0[6]; ++ ++ /* Saved main processor registers. */ ++ abi_ulong regs[32]; ++ ++ /* Saved special registers. */ ++ abi_ulong cp0_status; ++ abi_ulong lo; ++ abi_ulong hi; ++ abi_ulong cp0_badvaddr; ++ abi_ulong cp0_cause; ++ abi_ulong cp0_epc; ++}; ++ ++#define UNAME_MACHINE "mips" +diff --git a/bsd-user/mips/target_signal.h b/bsd-user/mips/target_signal.h +new file mode 100644 +index 0000000..28871c3 +--- /dev/null ++++ b/bsd-user/mips/target_signal.h +@@ -0,0 +1,14 @@ ++#ifndef TARGET_SIGNAL_H ++#define TARGET_SIGNAL_H ++ ++#include "cpu.h" ++ ++#define TARGET_MINSIGSTKSZ (512 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++ ++static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) ++{ ++ return state->active_tc.gpr[29]; ++} ++ ++#endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/mips/target_vmparam.h b/bsd-user/mips/target_vmparam.h +new file mode 100644 +index 0000000..9fca7f3 +--- /dev/null ++++ b/bsd-user/mips/target_vmparam.h +@@ -0,0 +1,30 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#if defined(__FreeBSD__) ++#define TARGET_VM_MINUSER_ADDRESS (0x00000000) ++#define TARGET_VM_MAXUSER_ADDRESS (0x80000000) ++ ++#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) ++ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#define TARGET_SZSIGCODE 0 ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++#endif ++ ++ ++#endif /* _TARGET_VMPARAM_H_ */ +diff --git a/bsd-user/mips64/syscall.h b/bsd-user/mips64/syscall.h +new file mode 100644 +index 0000000..fca3634 +--- /dev/null ++++ b/bsd-user/mips64/syscall.h +@@ -0,0 +1,21 @@ ++ ++/* this struct defines the way the registers are stored on the ++ stack during a system call. */ ++ ++struct target_pt_regs { ++ /* Saved main processor registers. */ ++ abi_ulong regs[32]; ++ ++ /* Saved special registers. */ ++ abi_ulong cp0_status; ++ abi_ulong lo; ++ abi_ulong hi; ++ abi_ulong cp0_badvaddr; ++ abi_ulong cp0_cause; ++ abi_ulong cp0_epc; ++}; ++ ++/* Nasty hack: define a fake errno value for use by sigreturn. */ ++#define TARGET_QEMU_ESIGRETURN 255 ++ ++#define UNAME_MACHINE "mips64" +diff --git a/bsd-user/mips64/target_signal.h b/bsd-user/mips64/target_signal.h +new file mode 100644 +index 0000000..d671f4e +--- /dev/null ++++ b/bsd-user/mips64/target_signal.h +@@ -0,0 +1,17 @@ ++#ifndef TARGET_SIGNAL_H ++#define TARGET_SIGNAL_H ++ ++#include "cpu.h" ++ ++#define TARGET_MINSIGSTKSZ (512 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++#define TARGET_SZSIGCODE 16 ++ ++#define TARGET_UCONTEXT_MAGIC 0xACEDBADE ++ ++static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) ++{ ++ return state->active_tc.gpr[29]; ++} ++ ++#endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/mips64/target_vmparam.h b/bsd-user/mips64/target_vmparam.h +new file mode 100644 +index 0000000..47c2267 +--- /dev/null ++++ b/bsd-user/mips64/target_vmparam.h +@@ -0,0 +1,28 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#if defined(__FreeBSD__) ++ ++#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL) ++#define TARGET_VM_MAXUSER_ADDRESS (0x0000008000000000UL) ++ ++#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) ++ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++#endif ++ ++#endif /* _TARGET_VMPARAM_H_ */ +diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c +index 5d6cffc..9f42c27 100644 +--- a/bsd-user/mmap.c ++++ b/bsd-user/mmap.c +@@ -275,7 +275,8 @@ unsigned long last_brk; + */ + /* page_init() marks pages used by the host as reserved to be sure not + to use them. */ +-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) ++abi_ulong ++mmap_find_vma(abi_ulong start, abi_ulong size) + { + abi_ulong addr, addr1, addr_start; + int prot; +@@ -493,7 +494,7 @@ int target_munmap(abi_ulong start, abi_ulong len) + int prot, ret; + + #ifdef DEBUG_MMAP +- printf("munmap: start=0x%lx len=0x%lx\n", start, len); ++ printf("munmap: start=0x" TARGET_FMT_lx " len=0x" TARGET_FMT_lx "\n", start, len); + #endif + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; +diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h +--- a/bsd-user/qemu.h ++++ b/bsd-user/qemu.h +@@ -20,9 +20,13 @@ enum BSDType { + }; + extern enum BSDType bsd_type; + ++abi_long memcpy_to_target(abi_ulong dest, const void *src, ++ unsigned long len); ++ + #include "syscall_defs.h" + #include "syscall.h" ++#include "target_vmparam.h" + #include "target_signal.h" + #include "exec/gdbstub.h" + + #if defined(CONFIG_USE_NPTL) +@@ -61,7 +65,7 @@ struct image_info { + + struct sigqueue { + struct sigqueue *next; +- //target_siginfo_t info; ++ target_siginfo_t info; + }; + + struct emulated_sigtable { +@@ -88,6 +92,7 @@ typedef struct TaskState { + uint32_t stack_base; + #endif + struct image_info *info; ++ struct bsd_binprm *bprm; + + struct emulated_sigtable sigtab[TARGET_NSIG]; + struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ +@@ -98,6 +103,8 @@ typedef struct TaskState { + } __attribute__((aligned(16))) TaskState; + + void init_task_state(TaskState *ts); ++void task_settid(TaskState *); ++void stop_all_tasks(void); + extern const char *qemu_uname_release; + #if defined(CONFIG_USE_GUEST_BASE) + extern unsigned long mmap_min_addr; +@@ -115,7 +122,7 @@ extern unsigned long mmap_min_addr; + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +-struct linux_binprm { ++struct bsd_binprm { + char buf[128]; + void *page[MAX_ARG_PAGES]; + abi_ulong p; +@@ -125,21 +132,21 @@ struct linux_binprm { + char **argv; + char **envp; + char * filename; /* Name of binary */ ++ int (*core_dump)(int, const CPUArchState *); /* coredump routine */ + }; + + void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); + abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + abi_ulong stringp, int push_ptr); + int loader_exec(const char * filename, char ** argv, char ** envp, +- struct target_pt_regs * regs, struct image_info *infop); ++ struct target_pt_regs * regs, struct image_info *infop, ++ struct bsd_binprm *); + +-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, ++int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); +-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, ++int load_flt_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); + +-abi_long memcpy_to_target(abi_ulong dest, const void *src, +- unsigned long len); + void target_set_brk(abi_ulong new_brk); + abi_long do_brk(abi_ulong new_brk); + void syscall_init(void); +@@ -184,10 +191,12 @@ extern int do_strace; + /* signal.c */ + void process_pending_signals(CPUArchState *cpu_env); + void signal_init(void); +-//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); +-//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +-//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +-long do_sigreturn(CPUArchState *env); ++int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); ++void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); ++void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); ++int target_to_host_signal(int sig); ++int host_to_target_signal(int sig); ++long do_sigreturn(CPUArchState *env, abi_ulong uc_addr); + long do_rt_sigreturn(CPUArchState *env); + abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); + +@@ -203,6 +212,7 @@ int target_msync(abi_ulong start, abi_ul + extern unsigned long last_brk; + void mmap_lock(void); + void mmap_unlock(void); ++abi_ulong mmap_find_vma(abi_ulong, abi_ulong); + void cpu_list_lock(void); + void cpu_list_unlock(void); + #if defined(CONFIG_USE_NPTL) +diff --git a/bsd-user/signal.c b/bsd-user/signal.c +index 445f69e..0502a6a 100644 +--- a/bsd-user/signal.c ++++ b/bsd-user/signal.c +@@ -2,6 +2,7 @@ + * Emulation of BSD signals + * + * Copyright (c) 2003 - 2008 Fabrice Bellard ++ * Copyright (c) 2012 Stacey Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -23,16 +24,1218 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "qemu.h" + #include "target_signal.h" + +-//#define DEBUG_SIGNAL ++// #define DEBUG_SIGNAL + +-void signal_init(void) ++#ifndef _NSIG ++#define _NSIG 128 ++#endif ++ ++static target_stack_t target_sigaltstack_used = { ++ .ss_sp = 0, ++ .ss_size = 0, ++ .ss_flags = TARGET_SS_DISABLE, ++}; ++ ++static uint8_t host_to_target_signal_table[_NSIG] = { ++ [SIGHUP] = TARGET_SIGHUP, ++ [SIGINT] = TARGET_SIGINT, ++ [SIGQUIT] = TARGET_SIGQUIT, ++ [SIGILL] = TARGET_SIGILL, ++ [SIGTRAP] = TARGET_SIGTRAP, ++ [SIGABRT] = TARGET_SIGABRT, ++ /* [SIGIOT] = TARGET_SIGIOT, */ ++ [SIGEMT] = TARGET_SIGEMT, ++ [SIGFPE] = TARGET_SIGFPE, ++ [SIGKILL] = TARGET_SIGKILL, ++ [SIGBUS] = TARGET_SIGBUS, ++ [SIGSEGV] = TARGET_SIGSEGV, ++ [SIGSYS] = TARGET_SIGSYS, ++ [SIGPIPE] = TARGET_SIGPIPE, ++ [SIGALRM] = TARGET_SIGALRM, ++ [SIGTERM] = TARGET_SIGTERM, ++ [SIGURG] = TARGET_SIGURG, ++ [SIGSTOP] = TARGET_SIGSTOP, ++ [SIGTSTP] = TARGET_SIGTSTP, ++ [SIGCONT] = TARGET_SIGCONT, ++ [SIGCHLD] = TARGET_SIGCHLD, ++ [SIGTTIN] = TARGET_SIGTTIN, ++ [SIGTTOU] = TARGET_SIGTTOU, ++ [SIGIO] = TARGET_SIGIO, ++ [SIGXCPU] = TARGET_SIGXCPU, ++ [SIGXFSZ] = TARGET_SIGXFSZ, ++ [SIGVTALRM] = TARGET_SIGVTALRM, ++ [SIGPROF] = TARGET_SIGPROF, ++ [SIGWINCH] = TARGET_SIGWINCH, ++ [SIGINFO] = TARGET_SIGINFO, ++ [SIGUSR1] = TARGET_SIGUSR1, ++ [SIGUSR2] = TARGET_SIGUSR2, ++#ifdef SIGTHR ++ [SIGTHR] = TARGET_SIGTHR, ++#endif ++ /* [SIGLWP] = TARGET_SIGLWP, */ ++#ifdef SIGLIBRT ++ [SIGLIBRT] = TARGET_SIGLIBRT, ++#endif ++ ++ /* ++ * The following signals stay the same. ++ * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with ++ * host libpthread signals. This assumes no one actually uses ++ * SIGRTMAX. To fix this properly we need to manual signal delivery ++ * multiplexed over a single host signal. ++ */ ++ [SIGRTMIN] = SIGRTMAX, ++ [SIGRTMAX] = SIGRTMIN, ++}; ++ ++static uint8_t target_to_host_signal_table[_NSIG]; ++ ++static struct target_sigaction sigact_table[TARGET_NSIG]; ++ ++static void host_signal_handler(int host_signum, siginfo_t *info, void *puc); ++ ++static inline int ++on_sig_stack(unsigned long sp) ++{ ++ return (sp - target_sigaltstack_used.ss_sp ++ < target_sigaltstack_used.ss_size); ++} ++ ++static inline int ++sas_ss_flags(unsigned long sp) ++{ ++ return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE ++ : on_sig_stack(sp) ? SS_ONSTACK : 0); ++} ++ ++int ++host_to_target_signal(int sig) ++{ ++ ++ if (sig >= _NSIG) ++ return (sig); ++ return (host_to_target_signal_table[sig]); ++} ++ ++int ++target_to_host_signal(int sig) ++{ ++ ++ if (sig >= _NSIG) ++ return (sig); ++ return (target_to_host_signal_table[sig]); ++} ++ ++static inline void ++target_sigemptyset(target_sigset_t *set) + { ++ memset(set, 0, sizeof(*set)); + } + +-void process_pending_signals(CPUArchState *cpu_env) ++static inline void ++target_sigaddset(target_sigset_t *set, int signum) + { ++ signum--; ++ uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW); ++ set->__bits[signum / TARGET_NSIG_BPW] |= mask; ++} ++ ++static inline int ++target_sigismember(const target_sigset_t *set, int signum) ++{ ++ signum--; ++ abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); ++ return ((set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0); ++} ++ ++static void ++host_to_target_sigset_internal(target_sigset_t *d, const sigset_t *s) ++{ ++ int i; ++ ++ target_sigemptyset(d); ++ for (i = 1; i <= TARGET_NSIG; i++) { ++ if (sigismember(s, i)) { ++ target_sigaddset(d, host_to_target_signal(i)); ++ } ++ } ++} ++ ++void ++host_to_target_sigset(target_sigset_t *d, const sigset_t *s) ++{ ++ target_sigset_t d1; ++ int i; ++ ++ host_to_target_sigset_internal(&d1, s); ++ for(i = 0;i < TARGET_NSIG_WORDS; i++) ++ d->__bits[i] = tswap32(d1.__bits[i]); ++} ++ ++static void ++target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) ++{ ++ int i; ++ ++ sigemptyset(d); ++ for (i = 1; i <= TARGET_NSIG; i++) { ++ if (target_sigismember(s, i)) { ++ sigaddset(d, target_to_host_signal(i)); ++ } ++ } ++} ++ ++void ++target_to_host_sigset(sigset_t *d, const target_sigset_t *s) ++{ ++ target_sigset_t s1; ++ int i; ++ ++ for(i = 0; i < TARGET_NSIG_WORDS; i++) ++ s1.__bits[i] = tswap32(s->__bits[i]); ++ target_to_host_sigset_internal(d, &s1); ++} ++ ++/* Siginfo conversion. */ ++static inline void ++host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) ++{ ++ int sig; ++ ++ sig = host_to_target_signal(info->si_signo); ++ tinfo->si_signo = sig; ++ tinfo->si_errno = info->si_errno; ++ tinfo->si_code = info->si_code; ++ tinfo->si_pid = info->si_pid; ++ tinfo->si_uid = info->si_uid; ++ tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr; ++ /* si_value is opaque to kernel */ ++ tinfo->si_value.sival_ptr = ++ (abi_ulong)(unsigned long)info->si_value.sival_ptr; ++ if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || ++ SIGBUS == sig || SIGTRAP == sig) { ++ tinfo->_reason._fault._trapno = info->_reason._fault._trapno; ++#ifdef SIGPOLL ++ } else if (SIGPOLL == sig) { ++ tinfo->_reason._poll._band = info->_reason._poll._band; ++#endif ++ } else { ++ tinfo->_reason._timer._timerid = info->_reason._timer._timerid; ++ tinfo->_reason._timer._overrun = info->_reason._timer._overrun; ++ } ++} ++ ++static void ++tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) ++{ ++ int sig; ++ sig = info->si_signo; ++ tinfo->si_signo = tswap32(sig); ++ tinfo->si_errno = tswap32(info->si_errno); ++ tinfo->si_code = tswap32(info->si_code); ++ tinfo->si_pid = tswap32(info->si_pid); ++ tinfo->si_uid = tswap32(info->si_uid); ++ tinfo->si_addr = tswapal(info->si_addr); ++ if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || ++ SIGBUS == sig || SIGTRAP == sig) { ++ tinfo->_reason._fault._trapno = ++ tswap32(info->_reason._fault._trapno); ++#ifdef SIGPOLL ++ } else if (SIGPOLL == sig) { ++ tinfo->_reason._poll._band = tswap32(info->_reason._poll._band); ++#endif ++ } else { ++ tinfo->_reason._timer._timerid = ++ tswap32(info->_reason._timer._timerid); ++ tinfo->_reason._timer._overrun = ++ tswap32(info->_reason._timer._overrun); ++ } ++} ++ ++void ++host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) ++{ ++ ++ host_to_target_siginfo_noswap(tinfo, info); ++ tswap_siginfo(tinfo, tinfo); ++} ++ ++/* Returns 1 if given signal should dump core if not handled. */ ++static int ++core_dump_signal(int sig) ++{ ++ switch (sig) { ++ case TARGET_SIGABRT: ++ case TARGET_SIGFPE: ++ case TARGET_SIGILL: ++ case TARGET_SIGQUIT: ++ case TARGET_SIGSEGV: ++ case TARGET_SIGTRAP: ++ case TARGET_SIGBUS: ++ return (1); ++ default: ++ return (0); ++ } ++} ++ ++/* Signal queue handling. */ ++static inline struct sigqueue * ++alloc_sigqueue(CPUArchState *env) ++{ ++ TaskState *ts = env->opaque; ++ struct sigqueue *q = ts->first_free; ++ ++ if (!q) ++ return (NULL); ++ ts->first_free = q->next; ++ return (q); ++} ++ ++static inline void ++free_sigqueue(CPUArchState *env, struct sigqueue *q) ++{ ++ ++ TaskState *ts = env->opaque; ++ q->next = ts->first_free; ++ ts->first_free = q; ++} ++ ++/* Abort execution with signal. */ ++static void QEMU_NORETURN ++force_sig(int target_sig) ++{ ++ TaskState *ts = (TaskState *)thread_env->opaque; ++ int host_sig, core_dumped = 0; ++ struct sigaction act; ++ ++ host_sig = target_to_host_signal(target_sig); ++ gdb_signalled(thread_env, target_sig); ++ ++ /* Dump core if supported by target binary format */ ++ if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) { ++ stop_all_tasks(); ++ core_dumped = ++ ((*ts->bprm->core_dump)(target_sig, thread_env) == 0); ++ } ++ if (core_dumped) { ++ struct rlimit nodump; ++ ++ /* ++ * We already dumped the core of target process, we don't want ++ * a coredump of qemu itself. ++ */ ++ getrlimit(RLIMIT_CORE, &nodump); ++ nodump.rlim_cur = 0; ++ (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) " ++ "- %s\n", target_sig, strsignal(host_sig), "core dumped"); ++ } ++ ++ /* ++ * The proper exit code for dying from an uncaught signal is ++ * -. The kernel doesn't allow exit() or _exit() to pass ++ * a negative value. To get the proper exit code we need to ++ * actually die from an uncaught signal. Here the default signal ++ * handler is installed, we send ourself a signal and we wait for ++ * it to arrive. ++ */ ++ memset(&act, 0, sizeof(act)); ++ sigfillset(&act.sa_mask); ++ act.sa_handler = SIG_DFL; ++ sigaction(host_sig, &act, NULL); ++ ++ kill(getpid(), host_sig); ++ ++ /* ++ * Make sure the signal isn't masked (just reuse the mask inside ++ * of act). ++ */ ++ sigdelset(&act.sa_mask, host_sig); ++ sigsuspend(&act.sa_mask); ++ ++ /* unreachable */ ++ abort(); ++} ++ ++/* ++ * Queue a signal so that it will be send to the virtual CPU as soon as ++ * possible. ++ */ ++int ++queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) ++{ ++ TaskState *ts = env->opaque; ++ struct emulated_sigtable *k; ++ struct sigqueue *q, **pq; ++ abi_ulong handler; ++ int queue; ++ ++ k = &ts->sigtab[sig - 1]; ++ queue = gdb_queuesig (); ++ handler = sigact_table[sig - 1]._sa_handler; ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig, ++ handler, (uint32_t)sigact_table[sig - 1].sa_flags); ++#endif ++ if (!queue && (TARGET_SIG_DFL == handler)) { ++ if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || ++ sig == TARGET_SIGTTOU) { ++ kill(getpid(), SIGSTOP); ++ return (0); ++ } else { ++ if (sig != TARGET_SIGCHLD && ++ sig != TARGET_SIGURG && ++ sig != TARGET_SIGWINCH && ++ sig != TARGET_SIGCONT) { ++ force_sig(sig); ++ } else { ++ return (0); /* The signal was ignored. */ ++ } ++ } ++ } else if (!queue && (TARGET_SIG_IGN == handler)) { ++ return (0); /* Ignored signal. */ ++ } else if (!queue && (TARGET_SIG_ERR == handler)) { ++ force_sig(sig); ++ } else { ++ pq = &k->first; ++ ++ /* ++ * FreeBSD signals are always queued. ++ * Linux only queues real time signals. ++ * XXX this code is not thread safe. ++ */ ++ if (!k->pending) { ++ /* first signal */ ++ q = &k->info; ++ } else { ++ q = alloc_sigqueue(env); ++ if (!q) ++ return (-EAGAIN); ++ while (*pq != NULL) ++ pq = &(*pq)->next; ++ } ++ *pq = q; ++ q->info = *info; ++ q->next = NULL; ++ k->pending = 1; ++ /* Signal that a new signal is pending. */ ++ ts->signal_pending = 1; ++ return (1); /* Indicates that the signal was queued. */ ++ } ++} ++ ++static void ++host_signal_handler(int host_signum, siginfo_t *info, void *puc) ++{ ++ int sig; ++ target_siginfo_t tinfo; ++ ++ /* ++ * The CPU emulator uses some host signal to detect exceptions so ++ * we forward to it some signals. ++ */ ++ if ((host_signum == SIGSEGV || host_signum == SIGBUS) && ++ info->si_code > 0) { ++ if (cpu_signal_handler(host_signum, info, puc)) ++ return; ++ } ++ ++ /* Get the target signal number. */ ++ sig = host_to_target_signal(host_signum); ++ if (sig < 1 || sig > TARGET_NSIG) ++ return; ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "qemu: got signal %d\n", sig); ++#endif ++ host_to_target_siginfo_noswap(&tinfo, info); ++ if (queue_signal(thread_env, sig, &tinfo) == 1) { ++ /* Interrupt the virtual CPU as soon as possible. */ ++ cpu_exit(thread_env); ++ } ++} ++ ++/* do_sigaltstack() returns target values and errnos. */ ++/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */ ++abi_long ++do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) ++{ ++ int ret = 0; ++ target_stack_t ss, oss, *uss; ++ ++ if (uoss_addr) { ++ /* Save current signal stack params */ ++ oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp); ++ oss.ss_size = tswapl(target_sigaltstack_used.ss_size); ++ oss.ss_flags = tswapl(sas_ss_flags(sp)); ++ } ++ ++ if (uss_addr) { ++ ++ if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) || ++ __get_user(ss.ss_sp, &uss->ss_sp) || ++ __get_user(ss.ss_size, &uss->ss_size) || ++ __get_user(ss.ss_flags, &uss->ss_flags)) { ++ ret = -TARGET_EFAULT; ++ goto out; ++ } ++ unlock_user_struct(uss, uss_addr, 0); ++ ++ if (on_sig_stack(sp)) { ++ ret = -TARGET_EPERM; ++ goto out; ++ } ++ ++ if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) { ++ ret = -TARGET_EINVAL; ++ goto out; ++ } ++ ++ if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) { ++ if (ss.ss_size < TARGET_MINSIGSTKSZ) { ++ ret = -TARGET_ENOMEM; ++ goto out; ++ } ++ } else { ++ ss.ss_size = 0; ++ ss.ss_sp = 0; ++ } ++ ++ target_sigaltstack_used.ss_sp = ss.ss_sp; ++ target_sigaltstack_used.ss_size = ss.ss_size; ++ } ++ ++ if (uoss_addr) { ++ /* Copy out to user saved signal stack params */ ++ if (copy_to_user(uoss_addr, &oss, sizeof(oss))) { ++ ret = -TARGET_EFAULT; ++ goto out; ++ } ++ } ++ ++out: ++ return (ret); ++} ++ ++static int ++fatal_signal(int sig) ++{ ++ ++ switch (sig) { ++ case TARGET_SIGCHLD: ++ case TARGET_SIGURG: ++ case TARGET_SIGWINCH: ++ /* Ignored by default. */ ++ return (0); ++ case TARGET_SIGCONT: ++ case TARGET_SIGSTOP: ++ case TARGET_SIGTSTP: ++ case TARGET_SIGTTIN: ++ case TARGET_SIGTTOU: ++ /* Job control signals. */ ++ return (0); ++ default: ++ return (1); ++ } ++} ++ ++/* do_sigaction() return host values and errnos */ ++int ++do_sigaction(int sig, const struct target_sigaction *act, ++ struct target_sigaction *oact) ++{ ++ struct target_sigaction *k; ++ struct sigaction act1; ++ int host_sig; ++ int ret = 0; ++ ++ if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig || ++ TARGET_SIGSTOP == sig) ++ return (-EINVAL); ++ k = &sigact_table[sig - 1]; ++#if defined(DEBUG_SIGNAL) ++ fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n", ++ sig, act, oact); ++#endif ++ if (oact) { ++ oact->_sa_handler = tswapal(k->_sa_handler); ++ oact->sa_flags = tswap32(k->sa_flags); ++ oact->sa_mask = k->sa_mask; ++ } ++ if (act) { ++ /* XXX: this is most likely not threadsafe. */ ++ k->_sa_handler = tswapal(act->_sa_handler); ++ k->sa_flags = tswap32(act->sa_flags); ++ k->sa_mask = act->sa_mask; ++ ++ /* Update the host signal state. */ ++ host_sig = target_to_host_signal(sig); ++ if (host_sig != SIGSEGV && host_sig != SIGBUS) { ++ memset(&act1, 0, sizeof(struct sigaction)); ++ sigfillset(&act1.sa_mask); ++ if (k->sa_flags & TARGET_SA_RESTART) ++ act1.sa_flags |= SA_RESTART; ++ /* ++ * Note: It is important to update the host kernel ++ * signal mask to avoid getting unexpected interrupted ++ * system calls. ++ */ ++ if (k->_sa_handler == TARGET_SIG_IGN) { ++ act1.sa_sigaction = (void *)SIG_IGN; ++ } else if (k->_sa_handler == TARGET_SIG_DFL) { ++ if (fatal_signal(sig)) ++ act1.sa_sigaction = ++ host_signal_handler; ++ else ++ act1.sa_sigaction = (void *)SIG_DFL; ++ } else { ++ act1.sa_flags = SA_SIGINFO; ++ act1.sa_sigaction = host_signal_handler; ++ } ++ ret = sigaction(host_sig, &act1, NULL); ++#if defined(DEBUG_SIGNAL) ++ fprintf(stderr, "sigaction (action = %p (host_signal_handler = %p)) returned: %d\n", act1.sa_sigaction, host_signal_handler, ret); ++#endif ++ } ++ } ++ return (ret); ++} ++ ++#if defined(TARGET_MIPS64) ++static inline int ++restore_sigmcontext(CPUMIPSState *regs, target_mcontext_t *mc) ++{ ++ int i, err = 0; ++ ++ for(i = 1; i < 32; i++) ++ err |= __get_user(regs->active_tc.gpr[i], ++ &mc->mc_regs[i]); ++ err |= __get_user(regs->CP0_EPC, &mc->mc_pc); ++ err |= __get_user(regs->active_tc.LO[0], &mc->mullo); ++ err |= __get_user(regs->active_tc.HI[0], &mc->mulhi); ++ err |= __get_user(regs->tls_value, &mc->mc_tls); /* XXX thread tls */ ++ ++#if 0 /* XXX */ ++ int used_fp = 0; ++ ++ err |= __get_user(used_fp, &mc->mc_fpused); ++ conditional_used_math(used_fp); ++ ++ preempt_disabled(); ++ if (used_math()) { ++ /* restore fpu context if we have used it before */ ++ own_fpu(); ++ err |= restore_fp_context(mc); ++ } else { ++ /* signal handler may have used FPU. Give it up. */ ++ lose_fpu(); ++ } ++ preempt_enable(); ++#endif ++ ++ return (err); ++} ++ ++static inline int ++setup_sigmcontext(CPUMIPSState *regs, target_mcontext_t *mc, int32_t oonstack) ++{ ++ int i, err = 0; ++ abi_long ucontext_magic = TARGET_UCONTEXT_MAGIC; ++ ++ err = __put_user(oonstack ? 1 : 0, &mc->mc_onstack); ++ err |= __put_user(regs->active_tc.PC, &mc->mc_pc); ++ err |= __put_user(regs->active_tc.LO[0], &mc->mullo); ++ err |= __put_user(regs->active_tc.HI[0], &mc->mulhi); ++ err |= __put_user(regs->tls_value, &mc->mc_tls); /* XXX thread tls */ ++ ++ err |= __put_user(ucontext_magic, &mc->mc_regs[0]); ++ for(i = 1; i < 32; i++) ++ err |= __put_user(regs->active_tc.gpr[i], &mc->mc_regs[i]); ++ ++ err |= __put_user(0, &mc->mc_fpused); ++ ++#if 0 /* XXX */ ++ err |= __put_user(used_math(), &mc->mc_fpused); ++ if (used_math()) ++ goto out; ++ ++ /* ++ * Save FPU state to signal context. Signal handler will "inherit" ++ * current FPU state. ++ */ ++ preempt_disable(); ++ ++ if (!is_fpu_owner()) { ++ own_fpu(); ++ for(i = 0; i < 33; i++) ++ err |= __put_user(regs->active_tc.fpregs[i], &mc->mc_fpregs[i]); ++ } ++ err |= save_fp_context(fg); ++ ++ preempt_enable(); ++out: ++#endif ++ return (err); ++} ++ ++static inline abi_ulong ++get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) ++{ ++ abi_ulong sp; ++ ++ /* Use default user stack */ ++ sp = regs->active_tc.gpr[29]; ++ ++ if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { ++ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; ++ } ++ ++ return ((sp - frame_size) & ~7); ++} ++ ++/* compare to mips/mips/pm_machdep.c sendsig() */ ++static void setup_frame(int sig, struct target_sigaction *ka, ++ target_sigset_t *set, CPUMIPSState *regs) ++{ ++ struct target_sigframe *frame; ++ abi_ulong frame_addr; ++ int i; ++ ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "setup_frame()\n"); ++#endif ++ ++ frame_addr = get_sigframe(ka, regs, sizeof(*frame)); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) ++ goto give_sigsegv; ++ ++ if (setup_sigmcontext(regs, &frame->sf_uc.uc_mcontext, ++ ! on_sig_stack(frame_addr))) ++ goto give_sigsegv; ++ ++ for(i = 0; i < TARGET_NSIG_WORDS; i++) { ++ if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) ++ goto give_sigsegv; ++ } ++ ++ /* fill in sigframe structure */ ++ if (__put_user(sig, &frame->sf_signum)) ++ goto give_sigsegv; ++ if (__put_user(0, &frame->sf_siginfo)) ++ goto give_sigsegv; ++ if (__put_user(0, &frame->sf_ucontext)) ++ goto give_sigsegv; ++ ++ /* fill in siginfo structure */ ++ if (__put_user(sig, &frame->sf_si.si_signo)) ++ goto give_sigsegv; ++ if (__put_user(TARGET_SA_SIGINFO, &frame->sf_si.si_code)) ++ goto give_sigsegv; ++ if (__put_user(regs->CP0_BadVAddr, &frame->sf_si.si_addr)) ++ goto give_sigsegv; ++ ++ /* ++ * Arguments to signal handler: ++ * a0 ($4) = signal number ++ * a1 ($5) = siginfo pointer ++ * a2 ($6) = ucontext pointer ++ * PC = signal handler pointer ++ * t9 ($25) = signal handler pointer ++ * $29 = point to sigframe struct ++ * ra ($31) = sigtramp at base of user stack ++ */ ++ regs->active_tc.gpr[ 4] = sig; ++ regs->active_tc.gpr[ 5] = frame_addr + ++ offsetof(struct target_sigframe, sf_si); ++ regs->active_tc.gpr[ 6] = frame_addr + ++ offsetof(struct target_sigframe, sf_uc); ++ regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; ++ regs->active_tc.gpr[29] = frame_addr; ++ regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; ++ unlock_user_struct(frame, frame_addr, 1); ++ return; ++ ++give_sigsegv: ++ unlock_user_struct(frame, frame_addr, 1); ++ force_sig(TARGET_SIGSEGV); ++} ++ ++long ++do_sigreturn(CPUMIPSState *regs, abi_ulong uc_addr) ++{ ++ target_ucontext_t *ucontext; ++ sigset_t blocked; ++ target_sigset_t target_set; ++ int i; ++ ++#if defined(DEBUG_SIGNAL) ++ fprintf(stderr, "do_sigreturn\n"); ++#endif ++ if (!lock_user_struct(VERIFY_READ, ucontext, uc_addr, 1)) ++ goto badframe; ++ ++ for(i = 0; i < TARGET_NSIG_WORDS; i++) { ++ if (__get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i])) ++ goto badframe; ++ } ++ ++ if (restore_sigmcontext(regs, &ucontext->uc_mcontext)) ++ goto badframe; ++ ++ target_to_host_sigset_internal(&blocked, &target_set); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ ++ regs->active_tc.PC = regs->CP0_EPC; ++ regs->CP0_EPC = 0; /* XXX for nested signals ? */ ++ return (-TARGET_QEMU_ESIGRETURN); ++ ++badframe: ++ force_sig(TARGET_SIGSEGV); ++ return (0); ++} ++ ++#elif defined(TARGET_SPARC64) ++ ++extern abi_ulong sparc_user_sigtramp; ++ ++#define mc_flags mc_global[0] ++#define mc_sp mc_out[6] ++#define mc_fprs mc_local[0] ++#define mc_fsr mc_local[1] ++#define mc_qsr mc_local[2] ++#define mc_tnpc mc_in[0] ++#define mc_tpc mc_in[1] ++#define mc_tstate mc_in[2] ++#define mc_y mc_in[4] ++#define mc_wstate mc_in[5] ++ ++#define ureg_i0 regwptr[0 ] ++#define ureg_i1 regwptr[1 ] ++#define ureg_i2 regwptr[2 ] ++#define ureg_i3 regwptr[3 ] ++#define ureg_i4 regwptr[4 ] ++#define ureg_i5 regwptr[5 ] ++#define ureg_i6 regwptr[6 ] ++#define ureg_i7 regwptr[7 ] ++#define ureg_l0 regwptr[8 ] ++#define ureg_l1 regwptr[9 ] ++#define ureg_l2 regwptr[10] ++#define ureg_l3 regwptr[11] ++#define ureg_l4 regwptr[12] ++#define ureg_l5 regwptr[13] ++#define ureg_l6 regwptr[14] ++#define ureg_l7 regwptr[15] ++#define ureg_o0 regwptr[16] ++#define ureg_o1 regwptr[17] ++#define ureg_o2 regwptr[18] ++#define ureg_o3 regwptr[19] ++#define ureg_o4 regwptr[20] ++#define ureg_o5 regwptr[21] ++#define ureg_o6 regwptr[22] ++#define ureg_o7 regwptr[23] ++#define ureg_fp ureg_i6 ++#define ureg_sp ureg_o6 ++#define ureg_tnpc ureg_i0 ++#define ureg_tpc ureg_i1 ++ ++#define TARGET_FPRS_FEF (1 << 2) ++#define TARGET_MC_VERSION 1L ++ ++/* compare to sparc64/sparc64/machdep.c set_mcontext() */ ++static inline int ++restore_sigmcontext(CPUSPARCState *regs, target_mcontext_t *mc) ++{ ++ int err = 0; ++ ++ err |= __get_user(regs->gregs[1], &mc->mc_global[1]); ++ err |= __get_user(regs->gregs[2], &mc->mc_global[2]); ++ err |= __get_user(regs->gregs[3], &mc->mc_global[3]); ++ err |= __get_user(regs->gregs[4], &mc->mc_global[4]); ++ err |= __get_user(regs->gregs[5], &mc->mc_global[5]); ++ err |= __get_user(regs->gregs[6], &mc->mc_global[6]); ++ ++ err |= __get_user(regs->ureg_o0, &mc->mc_out[0]); ++ err |= __get_user(regs->ureg_o1, &mc->mc_out[1]); ++ err |= __get_user(regs->ureg_o2, &mc->mc_out[2]); ++ err |= __get_user(regs->ureg_o3, &mc->mc_out[3]); ++ err |= __get_user(regs->ureg_o4, &mc->mc_out[4]); ++ err |= __get_user(regs->ureg_o5, &mc->mc_out[5]); ++ err |= __get_user(regs->ureg_o6, &mc->mc_out[6]); ++ err |= __get_user(regs->ureg_o7, &mc->mc_out[0]); ++ ++ err |= __get_user(regs->ureg_l0, &mc->mc_fprs); /* mc_local[0] */ ++ err |= __get_user(regs->ureg_l1, &mc->mc_fsr); /* mc_local[1] */ ++ err |= __get_user(regs->ureg_l2, &mc->mc_qsr); /* mc_local[2] */ ++ ++ err |= __get_user(regs->ureg_i0, &mc->mc_tnpc); /* mc_in[0] */ ++ err |= __get_user(regs->ureg_i1, &mc->mc_tpc); /* mc_in[1] */ ++ err |= __get_user(regs->ureg_i2, &mc->mc_tstate);/* mc_in[2] */ ++ ++ err |= __get_user(regs->ureg_i4, &mc->mc_y); /* mc_in[4] */ ++ ++ /* XXX ++ if ((regs->ureg_l0 & TARGET_FPRS_FEF) != 0) { ++ regs->ureg_l0 = 0; ++ for(i = 0; i < 64; i++) ++ err |= __get_user(regs->fpr[i], &mc->mc_fp[i]); ++ } ++ */ ++ ++ return (err); ++} ++ ++/* compare to sparc64/sparc64/machdep.c get_mcontext() */ ++static inline int ++setup_sigmcontext(CPUSPARCState *regs, target_mcontext_t *mc) ++{ ++ int err = 0; ++ abi_ulong ver = TARGET_MC_VERSION; ++ ++ err |= __put_user(ver, &mc->mc_flags); /* aka. mc_global[0] */ ++ err |= __put_user(regs->gregs[1], &mc->mc_global[1]); ++ err |= __put_user(regs->gregs[2], &mc->mc_global[2]); ++ err |= __put_user(regs->gregs[3], &mc->mc_global[3]); ++ err |= __put_user(regs->gregs[4], &mc->mc_global[4]); ++ err |= __put_user(regs->gregs[5], &mc->mc_global[5]); ++ err |= __put_user(regs->gregs[6], &mc->mc_global[6]); ++ /* skip %g7 since it is used as the userland TLS register */ ++ ++ err |= __put_user(regs->ureg_o0, &mc->mc_out[0]); ++ err |= __put_user(regs->ureg_o1, &mc->mc_out[1]); ++ err |= __put_user(regs->ureg_o2, &mc->mc_out[2]); ++ err |= __put_user(regs->ureg_o3, &mc->mc_out[3]); ++ err |= __put_user(regs->ureg_o4, &mc->mc_out[4]); ++ err |= __put_user(regs->ureg_o5, &mc->mc_out[5]); ++ err |= __put_user(regs->ureg_o6, &mc->mc_out[6]); ++ err |= __put_user(regs->ureg_o7, &mc->mc_out[7]); ++ ++ err |= __put_user(regs->ureg_l0, &mc->mc_fprs); /* mc_local[0] */ ++ err |= __put_user(regs->ureg_l1, &mc->mc_fsr); /* mc_local[1] */ ++ err |= __put_user(regs->ureg_l2, &mc->mc_qsr); /* mc_local[2] */ ++ ++ err |= __put_user(regs->ureg_i0, &mc->mc_tnpc); /* mc_in[0] */ ++ err |= __put_user(regs->ureg_i1, &mc->mc_tpc); /* mc_in[1] */ ++ err |= __put_user(regs->ureg_i2, &mc->mc_tstate);/* mc_in[2] */ ++ ++ err |= __put_user(regs->ureg_i4, &mc->mc_y); /* mc_in[4] */ ++ ++ /* XXX ++ if ((regs->ureg_l0 & TARGET_FPRS_FEF) != 0) { ++ for(i = 0; i < 64; i++) ++ err |= __put_user(regs->fpr[i], &mc->mc_fp[i]); ++ } ++ */ ++ ++ return (err); ++} ++ ++static inline abi_ulong ++get_sigframe(struct target_sigaction *ka, CPUSPARCState *regs, size_t frame_size) ++{ ++ abi_ulong sp; ++ ++ /* Use default user stack */ ++ sp = regs->ureg_sp; ++ ++ if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { ++ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; ++ } ++ ++ return (sp - frame_size); ++} ++ ++/* compare to sparc64/sparc64/machdep.c sendsig() */ ++static void setup_frame(int sig, struct target_sigaction *ka, ++ target_sigset_t *set, CPUSPARCState *regs) ++{ ++ struct target_sigframe *frame; ++ abi_ulong frame_addr; ++ int i; ++ ++ if (!sparc_user_sigtramp) { ++ /* No signal trampoline... kill the process. */ ++ fprintf(stderr, "setup_frame(): no sigtramp\n"); ++ force_sig(TARGET_SIGKILL); ++ } ++ ++ frame_addr = get_sigframe(ka, regs, sizeof(*frame)); ++ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) ++ goto give_sigsegv; ++ ++ if (setup_sigmcontext(regs, &frame->sf_uc.uc_mcontext)) ++ goto give_sigsegv; ++ ++ for(i = 0; i < TARGET_NSIG_WORDS; i++) { ++ if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) ++ goto give_sigsegv; ++ } ++ ++ /* Fill in siginfo structure */ ++ if (__put_user(sig, &frame->sf_si.si_signo)) ++ goto give_sigsegv; ++ if (__put_user(TARGET_SA_SIGINFO, &frame->sf_si.si_code)) ++ goto give_sigsegv; ++ ++ /* Arguments to signal handler: ++ * ++ * o0 = signal number ++ * o1 = pointer to siginfo struct ++ * o2 = pointer to ucontext struct ++ * o3 = (not used in new style) ++ * o4 = signal handler address (called by sigtramp) ++ */ ++ regs->ureg_o0 = sig; ++ regs->ureg_o1 = frame_addr + ++ offsetof(struct target_sigframe, sf_si); ++ regs->ureg_o2 = frame_addr + ++ offsetof(struct target_sigframe, sf_uc); ++ /* env->ureg_o3 used in the Old FreeBSD-style arguments. */ ++ regs->ureg_o4 = ka->_sa_handler; ++ ++ regs->ureg_tpc = sparc_user_sigtramp; ++ regs->ureg_tnpc = (regs->ureg_tpc + 4); ++ regs->ureg_sp = frame_addr - 2047 /* SPOFF */; ++ unlock_user_struct(frame, frame_addr, 1); ++ return; ++ ++give_sigsegv: ++ unlock_user_struct(frame, frame_addr, 1); ++ force_sig(TARGET_SIGSEGV); ++} ++ ++ ++long do_sigreturn(CPUSPARCState *regs, abi_ulong uc_addr) ++{ ++ target_ucontext_t *ucontext; ++ sigset_t blocked; ++ target_sigset_t target_set; ++ int i; ++ ++#if defined(DEBUG_SIGNAL) ++ fprintf(stderr, "do_sigreturn\n"); ++#endif ++ if (!lock_user_struct(VERIFY_READ, ucontext, uc_addr, 1)) ++ goto badframe; ++ ++ for(i = 0; i < TARGET_NSIG_WORDS; i++) { ++ if (__get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i])) ++ goto badframe; ++ } ++ ++ if (restore_sigmcontext(regs, &ucontext->uc_mcontext)) ++ goto badframe; ++ ++ target_to_host_sigset_internal(&blocked, &target_set); ++ sigprocmask(SIG_SETMASK, &blocked, NULL); ++ ++ return (-TARGET_QEMU_ESIGRETURN); ++ ++badframe: ++ force_sig(TARGET_SIGSEGV); ++ return (0); ++} ++ ++#else ++ ++static void ++setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, ++ CPUArchState *env) ++{ ++ fprintf(stderr, "setup_frame: not implemented\n"); ++} ++ ++#if 0 ++static void ++setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, ++ target_sigset_t *set, CPUArchState *env) ++{ ++ fprintf(stderr, "setup_rt_frame: not implemented\n"); ++} ++#endif ++ ++long ++do_sigreturn(CPUArchState *env, abi_ulong uc_addr) ++{ ++ fprintf(stderr,"do_sigreturn: not implemented\n"); ++ return (-TARGET_ENOSYS); ++} ++ ++long ++do_rt_sigreturn(CPUArchState *env) ++{ ++ fprintf(stderr, "do_rt_sigreturn: not implemented\n"); ++ return (-TARGET_ENOSYS); ++} ++#endif ++ ++void ++signal_init(void) ++{ ++ struct sigaction act; ++ struct sigaction oact; ++ int i, j; ++ int host_sig; ++ ++ /* Generate the signal conversion tables. */ ++ for(i = 1; i < _NSIG; i++) { ++ if (host_to_target_signal_table[i] == 0) ++ host_to_target_signal_table[i] = i; ++ } ++ for(i = 1; i < _NSIG; i++) { ++ j = host_to_target_signal_table[i]; ++ target_to_host_signal_table[j] = i; ++ } ++ ++ /* ++ * Set all host signal handlers. ALL signals are blocked during the ++ * handlers to serialize them. ++ */ ++ memset(sigact_table, 0, sizeof(sigact_table)); ++ ++ sigfillset(&act.sa_mask); ++ act.sa_sigaction = host_signal_handler; ++ ++ for (i = 1; i <= TARGET_NSIG; i++) { ++ host_sig = target_to_host_signal(i); ++ sigaction(host_sig, NULL, &oact); ++ if (oact.sa_sigaction == (void *)SIG_IGN) { ++ sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; ++ } else if (oact.sa_sigaction == (void *)SIG_DFL) { ++ sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; ++ } ++ /* ++ * If there's already a handler installed then something has ++ * gone horribly wrong, so don't even try to handle that case. ++ * Install some handlers for our own use. We need at least ++ * SIGSEGV and SIGBUS, to detect exceptions. We can not just ++ * trap all signals because it affects syscall interrupt ++ * behavior. But do trap all default-fatal signals. ++ */ ++ if (fatal_signal(i)) { ++ sigaction(host_sig, &act, NULL); ++ } ++ } ++} ++ ++void ++process_pending_signals(CPUArchState *cpu_env) ++{ ++ int sig; ++ abi_ulong handler; ++ sigset_t set, old_set; ++ target_sigset_t target_old_set; ++ struct emulated_sigtable *k; ++ struct target_sigaction *sa; ++ struct sigqueue *q; ++ TaskState *ts = cpu_env->opaque; ++ ++ if (!ts->signal_pending) ++ return; ++ ++ /* FIXME: This is not threadsafe. */ ++ k = ts->sigtab; ++ for(sig = 1; sig <= TARGET_NSIG; sig++) { ++ if (k->pending) ++ goto handle_signal; ++ k++; ++ } ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "qemu: process_pending_signals has no signals\n"); ++#endif ++ /* If no signal is pending then just return. */ ++ ts->signal_pending = 0; ++ return; ++ ++handle_signal: ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "qemu: process signal %d\n", sig); ++#endif ++ ++ /* Dequeue signal. */ ++ q = k->first; ++ k->first = q->next; ++ if (!k->first) ++ k->pending = 0; ++ ++ sig = gdb_handlesig (cpu_env, sig); ++ if (!sig) { ++ sa = NULL; ++ handler = TARGET_SIG_IGN; ++ } else { ++ sa = &sigact_table[sig - 1]; ++ handler = sa->_sa_handler; ++ } ++ ++ if (handler == TARGET_SIG_DFL) { ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "qemu: TARGET_SIG_DFL\n"); ++#endif ++ /* ++ * default handler : ignore some signal. The other are job ++ * control or fatal. ++ */ ++ if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig || ++ TARGET_SIGTTOU == sig) { ++ kill(getpid(),SIGSTOP); ++ } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig && ++ TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) { ++ force_sig(sig); ++ } ++ } else if (TARGET_SIG_IGN == handler) { ++ /* ignore sig */ ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "qemu: TARGET_SIG_IGN\n"); ++#endif ++ } else if (TARGET_SIG_ERR == handler) { ++#ifdef DEBUG_SIGNAL ++ fprintf(stderr, "qemu: TARGET_SIG_ERR\n"); ++#endif ++ force_sig(sig); ++ } else { ++ /* compute the blocked signals during the handler execution */ ++ target_to_host_sigset(&set, &sa->sa_mask); ++ /* ++ * SA_NODEFER indicates that the current signal should not be ++ * blocked during the handler. ++ */ ++ if (!(sa->sa_flags & TARGET_SA_NODEFER)) ++ sigaddset(&set, target_to_host_signal(sig)); ++ ++ /* block signals in the handler */ ++ sigprocmask(SIG_BLOCK, &set, &old_set); ++ ++ /* ++ * Save the previous blocked signal state to restore it at the ++ * end of the signal execution (see do_sigreturn). ++ */ ++ host_to_target_sigset_internal(&target_old_set, &old_set); ++ ++#if 0 ++#if defined(TARGET_I386) && !defined(TARGET_X86_64) ++ /* if the CPU is in VM86 mode, we restore the 32 bit values */ ++ { ++ CPUX86State *env = cpu_env; ++ if (env->eflags & VM_MASK) ++ save_v86_state(env); ++ } ++#endif ++#endif ++ /* prepare the stack frame of the virtual CPU */ ++#if 0 /* XXX no rt for fbsd */ ++ if (sa->sa_flags & TARGET_SA_SIGINFO) ++ setup_rt_frame(sig, sa, &q->info, &target_old_set, ++ cpu_env); ++ else ++#endif ++ setup_frame(sig, sa, &target_old_set, cpu_env); ++ if (sa->sa_flags & TARGET_SA_RESETHAND) ++ sa->_sa_handler = TARGET_SIG_DFL; ++ } ++ if (q != &k->info) ++ free_sigqueue(cpu_env, q); + } +diff --git a/bsd-user/socket.h b/bsd-user/socket.h +new file mode 100644 +index 0000000..c9e019b +--- /dev/null ++++ b/bsd-user/socket.h +@@ -0,0 +1,66 @@ ++/* ++ * Target socket definitions. ++ */ ++ ++/* ++ * Types ++ */ ++#define TARGET_SOCK_STREAM 1 /* stream socket */ ++#define TARGET_SOCK_DGRAM 2 /* datagram socket */ ++#define TARGET_SOCK_RAW 3 /* raw-protocol interface */ ++#define TARGET_SOCK_RDM 4 /* reliably-delivered message */ ++#define TARGET_SOCK_SEQPACKET 5 /* sequenced packet stream */ ++ ++ ++/* ++ * Option flags per-socket. ++ */ ++ ++#define TARGET_SO_DEBUG 0x0001 /* turn on debugging info recording */ ++#define TARGET_SO_ACCEPTCONN 0x0002 /* socket has had listen() */ ++#define TARGET_SO_REUSEADDR 0x0004 /* allow local address reuse */ ++#define TARGET_SO_KEEPALIVE 0x0008 /* keep connections alive */ ++#define TARGET_SO_DONTROUTE 0x0010 /* just use interface addresses */ ++#define TARGET_SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ ++#define TARGET_SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ ++#define TARGET_SO_LINGER 0x0080 /* linger on close if data present */ ++#define TARGET_SO_OOBINLINE 0x0100 /* leave received OOB data in line */ ++#define TARGET_SO_REUSEPORT 0x0200 /* allow local address & port reuse */ ++#define TARGET_SO_TIMESTAMP 0x0400 /* timestamp received dgram traffic */ ++#define TARGET_SO_NOSIGPIPE 0x0800 /* no SIGPIPE from EPIPE */ ++#define TARGET_SO_ACCEPTFILTER 0x1000 /* there is an accept filter */ ++#define TARGET_SO_BINTIME 0x2000 /* timestamp received dgram traffic */ ++#define TARGET_SO_NO_OFFLOAD 0x4000 /* socket cannot be offloaded */ ++#define TARGET_SO_NO_DDP 0x8000 /* disable direct data placement */ ++ ++/* ++ * Additional options, not kept in so_options. ++ */ ++#define TARGET_SO_SNDBUF 0x1001 /* send buffer size */ ++#define TARGET_SO_RCVBUF 0x1002 /* receive buffer size */ ++#define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ ++#define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ ++#define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ ++#define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ ++#define TARGET_SO_ERROR 0x1007 /* get error status and clear */ ++#define TARGET_SO_TYPE 0x1008 /* get socket type */ ++#define TARGET_SO_LABEL 0x1009 /* socket's MAC label */ ++#define TARGET_SO_PEERLABEL 0x1010 /* socket's peer's MAC label */ ++#define TARGET_SO_LISTENQLIMIT 0x1011 /* socket's backlog limit */ ++#define TARGET_SO_LISTENQLEN 0x1012 /* socket's complete queue length */ ++#define TARGET_SO_LISTENINCQLEN 0x1013 /* socket's incomplete queue length */ ++#define TARGET_SO_SETFIB 0x1014 /* use this FIB to route */ ++#define TARGET_SO_USER_COOKIE 0x1015 /* user cookie (dummynet etc.) */ ++#define TARGET_SO_PROTOCOL 0x1016 /* get socket protocol (Linux name) */ ++ ++/* alias for SO_PROTOCOL (SunOS name) */ ++#define TARGET_SO_PROTOTYPE TARGET_SO_PROTOCOL ++ ++/* ++ * Level number for (get/set)sockopt() to apply to socket itself. ++ */ ++#define TARGET_SOL_SOCKET 0xffff /* options for socket level */ ++ ++#ifndef CMSG_ALIGN ++#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) ) ++#endif +diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h +index 5b2abba..79dfc1e 100644 +--- a/bsd-user/sparc/target_signal.h ++++ b/bsd-user/sparc/target_signal.h +@@ -3,15 +3,6 @@ + + #include "cpu.h" + +-/* this struct defines a stack used during syscall handling */ +- +-typedef struct target_sigaltstack { +- abi_ulong ss_sp; +- abi_long ss_flags; +- abi_ulong ss_size; +-} target_stack_t; +- +- + #ifndef UREG_I6 + #define UREG_I6 6 + #endif +@@ -19,6 +10,9 @@ typedef struct target_sigaltstack { + #define UREG_FP UREG_I6 + #endif + ++#define TARGET_MINSIGSTKSZ (512 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++ + static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) + { + return state->regwptr[UREG_FP]; +diff --git a/bsd-user/sparc/target_vmparam.h b/bsd-user/sparc/target_vmparam.h +new file mode 100644 +index 0000000..9494c46 +--- /dev/null ++++ b/bsd-user/sparc/target_vmparam.h +@@ -0,0 +1,23 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#define TARGET_USRSTACK 0 ++ ++#ifdef __FreeBSD__ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#define TARGET_SZSIGCODE 0 ++#endif /* __FreeBSD__ */ ++ ++#endif /* _TARGET_VMPARAM_H_ */ ++ +diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h +index 5b2abba..d3e58bb 100644 +--- a/bsd-user/sparc64/target_signal.h ++++ b/bsd-user/sparc64/target_signal.h +@@ -3,15 +3,6 @@ + + #include "cpu.h" + +-/* this struct defines a stack used during syscall handling */ +- +-typedef struct target_sigaltstack { +- abi_ulong ss_sp; +- abi_long ss_flags; +- abi_ulong ss_size; +-} target_stack_t; +- +- + #ifndef UREG_I6 + #define UREG_I6 6 + #endif +@@ -19,6 +10,9 @@ typedef struct target_sigaltstack { + #define UREG_FP UREG_I6 + #endif + ++#define TARGET_MINSIGSTKSZ (1024 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++ + static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) + { + return state->regwptr[UREG_FP]; +diff --git a/bsd-user/sparc64/target_vmparam.h b/bsd-user/sparc64/target_vmparam.h +new file mode 100644 +index 0000000..12af063 +--- /dev/null ++++ b/bsd-user/sparc64/target_vmparam.h +@@ -0,0 +1,30 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#if defined(__FreeBSD__) ++#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL) ++#define TARGET_VM_MAXUSER_ADDRESS (0x000007fe00000000UL) ++ ++#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS ++ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#define TARGET_SZSIGCODE 0 ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++#endif ++ ++#endif /* _TARGET_VMPARAM_H_ */ ++ +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index 443b01a..c627c62 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -2,6 +2,7 @@ + * BSD syscalls + * + * Copyright (c) 2003 - 2008 Fabrice Bellard ++ * Copyright (c) 2012 Stacey Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -21,18 +22,37 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include ++#include + #include + #include + #include ++#include + #include ++#include ++#include ++#include ++#include ++#ifdef __FreeBSD__ ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include + #include + ++#include ++ + #include "qemu.h" + #include "qemu-common.h" + +@@ -50,6 +70,13 @@ static inline abi_long get_errno(abi_long ret) + return ret; + } + ++static inline int ++host_to_target_errno(int err) ++{ ++ /* XXX need to translate host errnos here */ ++ return (err); ++} ++ + #define target_to_host_bitmask(x, tbl) (x) + + static inline int is_error(abi_long ret) +@@ -152,13 +179,65 @@ static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms) + #endif + + #ifdef TARGET_SPARC ++struct target_sparc_sigtramp_install_args { ++ abi_ulong sia_new; /* address of sigtramp code */ ++ abi_ulong sia_old; /* user address to store old sigtramp addr */ ++}; ++ ++abi_ulong sparc_user_sigtramp = 0; ++ + static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + { +- /* XXX handle +- * TARGET_FREEBSD_SPARC_UTRAP_INSTALL, +- * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL +- */ +- return -TARGET_EINVAL; ++ int ret = 0; ++ abi_ulong val, old; ++ /* ++ struct target_sparc_sigtramp_install_args *target_sigtramp_args; ++ */ ++ ++ ++ switch(op) { ++ case TARGET_SPARC_SIGTRAMP_INSTALL: ++ { ++ ++#if 0 ++ /* Sparc userland is giving us a new sigtramp code ptr. */ ++ if (!(target_sigtramp_args = lock_user(VERIFY_WRITE, parms, ++ sizeof(*target_sigtramp_args), 1))) { ++ ret = -TARGET_EFAULT; ++ } else { ++ if (target_sigtramp_args->sia_old) { ++ put_user_ual(sparc_user_sigtramp, ++ target_sigtramp_args->sia_old); ++ } ++ sparc_user_sigtramp = target_sigtramp_args->sia_new; ++ unlock_user(target_sigtramp_args, parms, 0); ++ ++ } ++#endif ++ val = sparc_user_sigtramp; ++ if (get_user(sparc_user_sigtramp, parms, abi_ulong)) { ++ return (-TARGET_EFAULT); ++ } ++ parms += sizeof(abi_ulong); ++ if (get_user(old, parms, abi_ulong)) { ++ return (-TARGET_EFAULT); ++ } ++ if (old) { ++ if (put_user(val, old, abi_ulong)) { ++ return (-TARGET_EFAULT); ++ } ++ } ++ } ++ break; ++ ++ case TARGET_SPARC_UTRAP_INSTALL: ++ /* XXX not currently handled */ ++ default: ++ ret = -TARGET_EINVAL; ++ break; ++ } ++ ++ return (ret); + } + #endif + +@@ -168,7 +247,17 @@ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + return -TARGET_EINVAL; + } + #endif ++ ++#ifdef TARGET_MIPS ++static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) ++{ ++ return -TARGET_EINVAL; ++} ++#endif ++ + #ifdef __FreeBSD__ ++extern int _getlogin(char *, int); ++ + /* + * XXX this uses the undocumented oidfmt interface to find the kind of + * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() +@@ -327,92 +416,3799 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, + 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_. */ +-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 inline abi_long ++target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, ++ socklen_t len) + { +- abi_long ret; +- void *p; ++ const socklen_t unix_maxlen = sizeof (struct sockaddr_un); ++ sa_family_t sa_family; ++ struct target_sockaddr *target_saddr; + +-#ifdef DEBUG +- gemu_log("freebsd syscall %d\n", num); +-#endif +- if(do_strace) +- print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); ++ target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); ++ if (!target_saddr) ++ return -TARGET_EFAULT; + +- switch(num) { +- case TARGET_FREEBSD_NR_exit: +-#ifdef TARGET_GPROF +- _mcleanup(); ++ sa_family = tswap16(target_saddr->sa_family); ++ ++ /* ++ * Oops. The caller might send a incomplete sun_path; sun_path ++ * must be terminated by \0 (see the manual page), but unfortunately ++ * it is quite common to specify sockaddr_un length as ++ * "strlen(x->sun_path)" while it should be "strlen(...) + 1". We will ++ * fix that here if needed. ++ */ ++ if (sa_family == AF_UNIX) { ++ if (len < unix_maxlen && len > 0) { ++ char *cp = (char*)target_saddr; ++ ++ if ( cp[len-1] && !cp[len] ) ++ len++; ++ } ++ if (len > unix_maxlen) ++ len = unix_maxlen; ++ } ++ ++ memcpy(addr, target_saddr, len); ++ addr->sa_family = sa_family; ++ unlock_user(target_saddr, target_addr, 0); ++ ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr, ++ socklen_t len) ++{ ++ struct target_sockaddr *target_saddr; ++ ++ target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); ++ if (!target_saddr) ++ return (-TARGET_EFAULT); ++ memcpy(target_saddr, addr, len); ++ target_saddr->sa_family = tswap16(addr->sa_family); ++ unlock_user(target_saddr, target_addr, len); ++ ++ return (0); ++} ++ ++static inline abi_long ++target_to_host_cmsg(struct msghdr *msgh, struct target_msghdr *target_msgh) ++{ ++ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); ++ abi_long msg_controllen; ++ abi_ulong target_cmsg_addr; ++ struct target_cmsghdr *target_cmsg; ++ socklen_t space = 0; ++ ++ ++ msg_controllen = tswapal(target_msgh->msg_controllen); ++ if (msg_controllen < sizeof (struct target_cmsghdr)) ++ goto the_end; ++ target_cmsg_addr = tswapal(target_msgh->msg_control); ++ target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, ++ msg_controllen, 1); ++ if (!target_cmsg) ++ return (-TARGET_EFAULT); ++ while (cmsg && target_cmsg) { ++ void *data = CMSG_DATA(cmsg); ++ void *target_data = TARGET_CMSG_DATA(target_cmsg); ++ int len = tswapal(target_cmsg->cmsg_len) - ++ TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); ++ space += CMSG_SPACE(len); ++ if (space > msgh->msg_controllen) { ++ space -= CMSG_SPACE(len); ++ gemu_log("Host cmsg overflow\n"); ++ break; ++ } ++ cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level); ++ cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); ++ cmsg->cmsg_len = CMSG_LEN(len); ++ ++ if (cmsg->cmsg_level != TARGET_SOL_SOCKET || ++ cmsg->cmsg_type != SCM_RIGHTS) { ++ gemu_log("Unsupported ancillary data: %d/%d\n", ++ cmsg->cmsg_level, cmsg->cmsg_type); ++ memcpy(data, target_data, len); ++ } else { ++ int *fd = (int *)data; ++ int *target_fd = (int *)target_data; ++ int i, numfds = len / sizeof(int); ++ ++ for (i = 0; i < numfds; i++) ++ fd[i] = tswap32(target_fd[i]); ++ } ++ cmsg = CMSG_NXTHDR(msgh, cmsg); ++ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); ++ } ++ unlock_user(target_cmsg, target_cmsg_addr, 0); ++ ++the_end: ++ msgh->msg_controllen = space; ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_cmsg(struct target_msghdr *target_msgh, struct msghdr *msgh) ++{ ++ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); ++ abi_long msg_controllen; ++ abi_ulong target_cmsg_addr; ++ struct target_cmsghdr *target_cmsg; ++ socklen_t space = 0; ++ ++ msg_controllen = tswapal(target_msgh->msg_controllen); ++ if (msg_controllen < sizeof (struct target_cmsghdr)) ++ goto the_end; ++ target_cmsg_addr = tswapal(target_msgh->msg_control); ++ target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, ++ msg_controllen, 0); ++ if (!target_cmsg) ++ return (-TARGET_EFAULT); ++ while (cmsg && target_cmsg) { ++ void *data = CMSG_DATA(cmsg); ++ void *target_data = TARGET_CMSG_DATA(target_cmsg); ++ int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); ++ ++ space += TARGET_CMSG_SPACE(len); ++ if (space > msg_controllen) { ++ space -= TARGET_CMSG_SPACE(len); ++ gemu_log("Target cmsg overflow\n"); ++ break; ++ } ++ target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); ++ target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); ++ target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); ++ if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) && ++ (cmsg->cmsg_type == SCM_RIGHTS)) { ++ int *fd = (int *)data; ++ int *target_fd = (int *)target_data; ++ int i, numfds = len / sizeof(int); ++ for (i = 0; i < numfds; i++) ++ target_fd[i] = tswap32(fd[i]); ++ } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) && ++ (cmsg->cmsg_type == SO_TIMESTAMP) && ++ (len == sizeof(struct timeval))) { ++ /* copy struct timeval to target */ ++ struct timeval *tv = (struct timeval *)data; ++ struct target_timeval *target_tv = ++ (struct target_timeval *)target_data; ++ target_tv->tv_sec = tswapal(tv->tv_sec); ++ target_tv->tv_usec = tswapal(tv->tv_usec); ++ } else { ++ gemu_log("Unsupported ancillary data: %d/%d\n", ++ cmsg->cmsg_level, cmsg->cmsg_type); ++ memcpy(target_data, data, len); ++ } ++ cmsg = CMSG_NXTHDR(msgh, cmsg); ++ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); ++ } ++ unlock_user(target_cmsg, target_cmsg_addr, space); ++ ++the_end: ++ target_msgh->msg_controllen = tswapal(space); ++ return (0); ++} ++ ++static inline rlim_t ++target_to_host_rlim(abi_ulong target_rlim) ++{ ++ abi_ulong target_rlim_swap; ++ rlim_t result; ++ ++ target_rlim_swap = tswapal(target_rlim); ++ if (target_rlim_swap == TARGET_RLIM_INFINITY) ++ return (RLIM_INFINITY); ++ ++ result = target_rlim_swap; ++ if (target_rlim_swap != (rlim_t)result) ++ return (RLIM_INFINITY); ++ ++ return (result); ++} ++ ++static inline abi_ulong ++host_to_target_rlim(rlim_t rlim) ++{ ++ abi_ulong target_rlim_swap; ++ abi_ulong result; ++ ++ if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) ++ target_rlim_swap = TARGET_RLIM_INFINITY; ++ else ++ target_rlim_swap = rlim; ++ result = tswapal(target_rlim_swap); ++ ++ return (result); ++} ++ ++static inline int ++target_to_host_resource(int code) ++{ ++ ++ switch (code) { ++ case TARGET_RLIMIT_AS: ++ return RLIMIT_AS; ++ ++ case TARGET_RLIMIT_CORE: ++ return RLIMIT_CORE; ++ ++ case TARGET_RLIMIT_CPU: ++ return RLIMIT_CPU; ++ ++ case TARGET_RLIMIT_DATA: ++ return RLIMIT_DATA; ++ ++ case TARGET_RLIMIT_FSIZE: ++ return RLIMIT_FSIZE; ++ ++ case TARGET_RLIMIT_MEMLOCK: ++ return RLIMIT_MEMLOCK; ++ ++ case TARGET_RLIMIT_NOFILE: ++ return RLIMIT_NOFILE; ++ ++ case TARGET_RLIMIT_NPROC: ++ return RLIMIT_NPROC; ++ ++ case TARGET_RLIMIT_RSS: ++ return RLIMIT_RSS; ++ ++ case TARGET_RLIMIT_SBSIZE: ++ return RLIMIT_SBSIZE; ++ ++ case TARGET_RLIMIT_STACK: ++ return RLIMIT_STACK; ++ ++ case TARGET_RLIMIT_SWAP: ++ return RLIMIT_SWAP; ++ ++ case TARGET_RLIMIT_NPTS: ++ return RLIMIT_NPTS; ++ ++ default: ++ return (code); ++ } ++} ++ ++static int ++target_to_host_fcntl_cmd(int cmd) ++{ ++ ++ switch(cmd) { ++ case TARGET_F_DUPFD: ++ return F_DUPFD; ++ ++ case TARGET_F_DUP2FD: ++ return F_DUP2FD; ++ ++ case TARGET_F_GETFD: ++ return F_GETFD; ++ ++ case TARGET_F_SETFD: ++ return F_SETFD; ++ ++ case TARGET_F_GETFL: ++ return F_GETFL; ++ ++ case TARGET_F_SETFL: ++ return F_SETFL; ++ ++ case TARGET_F_GETOWN: ++ return F_GETOWN; ++ ++ case TARGET_F_SETOWN: ++ return F_SETOWN; ++ ++ case TARGET_F_GETLK: ++ return F_GETLK; ++ ++ case TARGET_F_SETLK: ++ return F_SETLK; ++ ++ case TARGET_F_SETLKW: ++ return F_SETLKW; ++ ++ case TARGET_F_READAHEAD: ++ return F_READAHEAD; ++ ++ case TARGET_F_RDAHEAD: ++ return F_RDAHEAD; ++ ++ default: ++ return (cmd); ++ } ++} ++ ++static inline abi_long ++host_to_target_rusage(abi_ulong target_addr, const struct rusage *rusage) ++{ ++ struct target_rusage *target_rusage; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ target_rusage->ru_utime.tv_sec = tswapal(rusage->ru_utime.tv_sec); ++ target_rusage->ru_utime.tv_usec = tswapal(rusage->ru_utime.tv_usec); ++ target_rusage->ru_stime.tv_sec = tswapal(rusage->ru_stime.tv_sec); ++ target_rusage->ru_stime.tv_usec = tswapal(rusage->ru_stime.tv_usec); ++ target_rusage->ru_maxrss = tswapal(rusage->ru_maxrss); ++ target_rusage->ru_ixrss = tswapal(rusage->ru_ixrss); ++ target_rusage->ru_idrss = tswapal(rusage->ru_idrss); ++ target_rusage->ru_isrss = tswapal(rusage->ru_isrss); ++ target_rusage->ru_minflt = tswapal(rusage->ru_minflt); ++ target_rusage->ru_majflt = tswapal(rusage->ru_majflt); ++ target_rusage->ru_nswap = tswapal(rusage->ru_nswap); ++ target_rusage->ru_inblock = tswapal(rusage->ru_inblock); ++ target_rusage->ru_oublock = tswapal(rusage->ru_oublock); ++ target_rusage->ru_msgsnd = tswapal(rusage->ru_msgsnd); ++ target_rusage->ru_msgrcv = tswapal(rusage->ru_msgrcv); ++ target_rusage->ru_nsignals = tswapal(rusage->ru_nsignals); ++ target_rusage->ru_nvcsw = tswapal(rusage->ru_nvcsw); ++ target_rusage->ru_nivcsw = tswapal(rusage->ru_nivcsw); ++ unlock_user_struct(target_rusage, target_addr, 1); ++ ++ return (0); ++} ++ ++/* ++ * Map host to target signal numbers for the wait family of syscalls. ++ * Assume all other status bits are the same. ++ */ ++static int ++host_to_target_waitstatus(int status) ++{ ++ if (WIFSIGNALED(status)) { ++ return (host_to_target_signal(WTERMSIG(status)) | ++ (status & ~0x7f)); ++ } ++ if (WIFSTOPPED(status)) { ++ return (host_to_target_signal(WSTOPSIG(status)) << 8) | ++ (status & 0xff); ++ } ++ return (status); ++} ++ ++static inline abi_long ++copy_from_user_timeval(struct timeval *tv, abi_ulong target_tv_addr) ++{ ++ struct target_freebsd_timeval *target_tv; ++ ++ if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 0)) ++ return -TARGET_EFAULT; ++ __get_user(tv->tv_sec, &target_tv->tv_sec); ++ __get_user(tv->tv_usec, &target_tv->tv_usec); ++ unlock_user_struct(target_tv, target_tv_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; ++ ++ if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 0)) ++ return -TARGET_EFAULT; ++ __get_user(ts->tv_sec, &target_ts->tv_sec); ++ __get_user(ts->tv_nsec, &target_ts->tv_nsec); ++ unlock_user_struct(target_ts, target_ts_addr, 1); ++ return (0); ++} ++ ++static inline abi_long ++fbsd_copy_to_user_timeval(struct timeval *tv, abi_ulong target_tv_addr) ++{ ++ struct target_freebsd_timeval *target_tv; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) ++ return -TARGET_EFAULT; ++ __put_user(tv->tv_sec, &target_tv->tv_sec); ++ __put_user(tv->tv_usec, &target_tv->tv_usec); ++ unlock_user_struct(target_tv, target_tv_addr, 1); ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_timespec(abi_ulong target_ts_addr, struct timespec *ts) ++{ ++ struct target_freebsd_timespec *target_ts; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0)) ++ return -TARGET_EFAULT; ++ __put_user(ts->tv_sec, &target_ts->tv_sec); ++ __put_user(ts->tv_nsec, &target_ts->tv_nsec); ++ unlock_user_struct(target_ts, target_ts_addr, 1); ++ return (0); ++} ++static inline abi_ulong ++copy_from_user_fdset(fd_set *fds, abi_ulong target_fds_addr, int n) ++{ ++ int i, nw, j, k; ++ abi_ulong b, *target_fds; ++ ++ nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; ++ if (!(target_fds = lock_user(VERIFY_READ, target_fds_addr, ++ sizeof(abi_ulong) * nw, 1))) ++ return (-TARGET_EFAULT); ++ ++ FD_ZERO(fds); ++ k = 0; ++ for (i = 0; i < nw; i++) { ++ /* grab the abi_ulong */ ++ __get_user(b, &target_fds[i]); ++ for (j = 0; j < TARGET_ABI_BITS; j++) { ++ /* check the bit inside the abi_ulong */ ++ if ((b >> j) & 1) ++ FD_SET(k, fds); ++ k++; ++ } ++ } ++ ++ unlock_user(target_fds, target_fds_addr, 0); ++ ++ return (0); ++} ++ ++static inline abi_ulong ++copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr, ++ abi_ulong target_fds_addr, int n) ++{ ++ if (target_fds_addr) { ++ if (copy_from_user_fdset(fds, target_fds_addr, n)) ++ return (-TARGET_EFAULT); ++ *fds_ptr = fds; ++ } else { ++ *fds_ptr = NULL; ++ } ++ return (0); ++} ++ ++static inline abi_long ++copy_to_user_fdset(abi_ulong target_fds_addr, const fd_set *fds, int n) ++{ ++ int i, nw, j, k; ++ abi_long v; ++ abi_ulong *target_fds; ++ ++ nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; ++ if (!(target_fds = lock_user(VERIFY_WRITE, target_fds_addr, ++ sizeof(abi_ulong) * nw, 0))) ++ return (-TARGET_EFAULT); ++ ++ k = 0; ++ for (i = 0; i < nw; i++) { ++ v = 0; ++ for (j = 0; j < TARGET_ABI_BITS; j++) { ++ v |= ((FD_ISSET(k, fds) != 0) << j); ++ k++; ++ } ++ __put_user(v, &target_fds[i]); ++ } ++ ++ unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw); ++ ++ return (0); ++} ++ ++#if TARGET_ABI_BITS == 32 ++static inline uint64_t ++target_offset64(uint32_t word0, uint32_t word1) ++{ ++#ifdef TARGET_WORDS_BIGENDIAN ++ return ((uint64_t)word0 << 32) | word1; ++#else ++ return ((uint64_t)word1 << 32) | word0; + #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_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; ++} ++#else /* TARGET_ABI_BITS != 32 */ ++static inline uint64_t ++target_offset64(uint64_t word0, uint64_t word1) ++{ ++ return (word0); ++} ++#endif /* TARGET_ABI_BITS != 32 */ + +- 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_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_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_break: +- ret = do_obreak(arg1); +- break; +-#ifdef __FreeBSD__ +- case TARGET_FREEBSD_NR___sysctl: +- ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); +- break; ++/* ARM EABI and MIPS expect 64bit types aligned even on pairs of registers */ ++#ifdef TARGET_ARM ++static inline int ++regpairs_aligned(void *cpu_env) { ++ ++ return ((((CPUARMState *)cpu_env)->eabi) == 1); ++} ++#elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32 ++static inline int ++regpairs_aligned(void *cpu_env) { return 1; } ++#else ++static inline int ++regpairs_aligned(void *cpu_env) { return 0; } + #endif +- case TARGET_FREEBSD_NR_sysarch: +- ret = do_freebsd_sysarch(cpu_env, arg1, arg2); +- break; +- case TARGET_FREEBSD_NR_syscall: +- case TARGET_FREEBSD_NR___syscall: +- ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0); +- break; ++ ++static inline abi_long ++unimplemented(int num) ++{ ++ ++ qemu_log("qemu: Unsupported syscall: %d\n", num); ++ return (-TARGET_ENOSYS); ++} ++ ++/* do_bind() must return target values and target errnos. */ ++static abi_long ++do_bind(int sockfd, abi_ulong target_addr, socklen_t addrlen) ++{ ++ abi_long ret; ++ void *addr; ++ ++ if ((int)addrlen < 0) ++ return (-TARGET_EINVAL); ++ ++ addr = alloca(addrlen + 1); ++ ret = target_to_host_sockaddr(addr, target_addr, addrlen); ++ if (ret) ++ return (ret); ++ ++ return get_errno(bind(sockfd, addr, addrlen)); ++} ++ ++/* do_connect() must return target values and target errnos. */ ++static abi_long ++do_connect(int sockfd, abi_ulong target_addr, socklen_t addrlen) ++{ ++ abi_long ret; ++ void *addr; ++ ++ if ((int)addrlen < 0) ++ return (-TARGET_EINVAL); ++ ++ addr = alloca(addrlen); ++ ++ ret = target_to_host_sockaddr(addr, target_addr, addrlen); ++ ++ if (ret) ++ return (ret); ++ ++ return (get_errno(connect(sockfd, addr, addrlen))); ++} ++ ++/* do_sendrecvmsg() must return target values and target errnos. */ ++static abi_long ++do_sendrecvmsg(int fd, abi_ulong target_msg, int flags, int send) ++{ ++ abi_long ret, len; ++ struct target_msghdr *msgp; ++ struct msghdr msg; ++ int count; ++ struct iovec *vec; ++ abi_ulong target_vec; ++ ++ if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, msgp, ++ target_msg, send ? 1 : 0)) ++ return (-TARGET_EFAULT); ++ if (msgp->msg_name) { ++ msg.msg_namelen = tswap32(msgp->msg_namelen); ++ msg.msg_name = alloca(msg.msg_namelen); ++ ret = target_to_host_sockaddr(msg.msg_name, ++ tswapal(msgp->msg_name), msg.msg_namelen); ++ ++ if (ret) { ++ unlock_user_struct(msgp, target_msg, send ? 0 : 1); ++ return (ret); ++ } ++ } else { ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ } ++ msg.msg_controllen = 2 * tswapal(msgp->msg_controllen); ++ msg.msg_control = alloca(msg.msg_controllen); ++ msg.msg_flags = tswap32(msgp->msg_flags); ++ ++ count = tswapal(msgp->msg_iovlen); ++ vec = alloca(count * sizeof(struct iovec)); ++ target_vec = tswapal(msgp->msg_iov); ++ lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, ++ send); ++ msg.msg_iovlen = count; ++ msg.msg_iov = vec; ++ ++ if (send) { ++ ret = target_to_host_cmsg(&msg, msgp); ++ if (0 == ret) ++ ret = get_errno(sendmsg(fd, &msg, flags)); ++ } else { ++ ret = get_errno(recvmsg(fd, &msg, flags)); ++ if (!is_error(ret)) { ++ len = ret; ++ ret = host_to_target_cmsg(msgp, &msg); ++ if (!is_error(ret)) { ++ msgp->msg_namelen = tswap32(msg.msg_namelen); ++ if (msg.msg_name != NULL) { ++ ret = host_to_target_sockaddr( ++ tswapal(msgp->msg_name), ++ msg.msg_name, msg.msg_namelen); ++ if (ret) ++ goto out; ++ } ++ } ++ ret = len; ++ } ++ } ++out: ++ unlock_iovec(vec, target_vec, count, !send); ++ unlock_user_struct(msgp, target_msg, send ? 0 : 1); ++ return (ret); ++} ++ ++/* do_accept() must return target values and target errnos. */ ++static abi_long ++do_accept(int fd, abi_ulong target_addr, abi_ulong target_addrlen_addr) ++{ ++ socklen_t addrlen; ++ void *addr; ++ abi_long ret; ++ ++ if (target_addr == 0) ++ return get_errno(accept(fd, NULL, NULL)); ++ ++ /* return EINVAL if addrlen pointer is invalid */ ++ if (get_user_u32(addrlen, target_addrlen_addr)) ++ return (-TARGET_EINVAL); ++ ++ if ((int)addrlen < 0) ++ return (-TARGET_EINVAL); ++ ++ if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) ++ return -TARGET_EINVAL; ++ ++ addr = alloca(addrlen); ++ ++ ret = get_errno(accept(fd, addr, &addrlen)); ++ if (!is_error(ret)) { ++ host_to_target_sockaddr(target_addr, addr, addrlen); ++ if (put_user_u32(addrlen, target_addrlen_addr)) ++ ret = (-TARGET_EFAULT); ++ } ++ return (ret); ++} ++ ++/* do_getpeername() must return target values and target errnos. */ ++static abi_long ++do_getpeername(int fd, abi_ulong target_addr, abi_ulong target_addrlen_addr) ++{ ++ socklen_t addrlen; ++ void *addr; ++ abi_long ret; ++ if (get_user_u32(addrlen, target_addrlen_addr)) ++ return (-TARGET_EFAULT); ++ if ((int)addrlen < 0) { ++ return (-TARGET_EINVAL); ++ } ++ if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) ++ return (-TARGET_EFAULT); ++ addr = alloca(addrlen); ++ ret = get_errno(getpeername(fd, addr, &addrlen)); ++ if (!is_error(ret)) { ++ host_to_target_sockaddr(target_addr, addr, addrlen); ++ if (put_user_u32(addrlen, target_addrlen_addr)) ++ ret = (-TARGET_EFAULT); ++ } ++ return (ret); ++} ++ ++/* do_getsockname() must return target values and target errnos. */ ++static abi_long ++do_getsockname(int fd, abi_ulong target_addr, abi_ulong target_addrlen_addr) ++{ ++ socklen_t addrlen; ++ void *addr; ++ abi_long ret; ++ ++ if (get_user_u32(addrlen, target_addrlen_addr)) ++ return (-TARGET_EFAULT); ++ ++ if ((int)addrlen < 0) ++ return (-TARGET_EINVAL); ++ ++ if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) ++ return (-TARGET_EFAULT); ++ ++ addr = alloca(addrlen); ++ ++ ret = get_errno(getsockname(fd, addr, &addrlen)); ++ if (!is_error(ret)) { ++ host_to_target_sockaddr(target_addr, addr, addrlen); ++ if (put_user_u32(addrlen, target_addrlen_addr)) ++ ret = (-TARGET_EFAULT); ++ } ++ return (ret); ++} ++ ++/* do_socketpair() must return target values and target errnos. */ ++static abi_long ++do_socketpair(int domain, int type, int protocol, abi_ulong target_tab_addr) ++{ ++ int tab[2]; ++ abi_long ret; ++ ++ ret = get_errno(socketpair(domain, type, protocol, tab)); ++ if (!is_error(ret)) { ++ if (put_user_s32(tab[0], target_tab_addr) ++ || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) ++ ret = (-TARGET_EFAULT); ++ } ++ return (ret); ++} ++ ++/* do_sendto() must return target values and target errnos. */ ++static abi_long ++do_sendto(int fd, abi_ulong msg, size_t len, int flags, abi_ulong target_addr, ++ socklen_t addrlen) ++{ ++ void *addr; ++ void *host_msg; ++ abi_long ret; ++ ++ if ((int)addrlen < 0) ++ return (-TARGET_EINVAL); ++ host_msg = lock_user(VERIFY_READ, msg, len, 1); ++ if (!host_msg) ++ return (-TARGET_EFAULT); ++ if (target_addr) { ++ addr = alloca(addrlen); ++ ret = target_to_host_sockaddr(addr, target_addr, addrlen); ++ if (ret) { ++ unlock_user(host_msg, msg, 0); ++ return (ret); ++ } ++ ret = get_errno(sendto(fd, host_msg, len, flags, addr, ++ addrlen)); ++ } else { ++ ret = get_errno(send(fd, host_msg, len, flags)); ++ } ++ unlock_user(host_msg, msg, 0); ++ return (ret); ++} ++ ++/* do_recvfrom() must return target values and target errnos. */ ++static abi_long ++do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, abi_ulong target_addr, ++ abi_ulong target_addrlen) ++{ ++ socklen_t addrlen; ++ void *addr; ++ void *host_msg; ++ abi_long ret; ++ ++ host_msg = lock_user(VERIFY_WRITE, msg, len, 0); ++ if (!host_msg) ++ return (-TARGET_EFAULT); ++ if (target_addr) { ++ if (get_user_u32(addrlen, target_addrlen)) { ++ ret = -TARGET_EFAULT; ++ goto fail; ++ } ++ if ((int)addrlen < 0) { ++ ret = (-TARGET_EINVAL); ++ goto fail; ++ } ++ addr = alloca(addrlen); ++ ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, ++ &addrlen)); ++ } else { ++ addr = NULL; /* To keep compiler quiet. */ ++ ret = get_errno(qemu_recv(fd, host_msg, len, flags)); ++ } ++ if (!is_error(ret)) { ++ if (target_addr) { ++ host_to_target_sockaddr(target_addr, addr, addrlen); ++ if (put_user_u32(addrlen, target_addrlen)) { ++ ret = -TARGET_EFAULT; ++ goto fail; ++ } ++ } ++ unlock_user(host_msg, msg, len); ++ } else { ++fail: ++ unlock_user(host_msg, msg, 0); ++ } ++ return (ret); ++} ++ ++/* do_freebsd_select() must return target values and target errnos. */ ++static abi_long ++do_freebsd_select(int n, abi_ulong rfd_addr, abi_ulong wfd_addr, ++ abi_ulong efd_addr, abi_ulong target_tv_addr) ++{ ++ fd_set rfds, wfds, efds; ++ fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; ++ struct timeval tv, *tv_ptr; ++ abi_long ret; ++ ++ if ((ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n)) != 0) ++ return (ret); ++ if ((ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n)) != 0) ++ return (ret); ++ if ((ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n)) != 0) ++ return (ret); ++ ++ if (target_tv_addr) { ++ if (copy_from_user_timeval(&tv, target_tv_addr)) ++ return (-TARGET_EFAULT); ++ tv_ptr = &tv; ++ } else { ++ tv_ptr = NULL; ++ } ++ ++ ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); ++ ++ if (!is_error(ret)) { ++ if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) ++ return (-TARGET_EFAULT); ++ if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) ++ return (-TARGET_EFAULT); ++ if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) ++ return (-TARGET_EFAULT); ++ ++ if (target_tv_addr && ++ fbsd_copy_to_user_timeval(&tv, target_tv_addr)) ++ return (-TARGET_EFAULT); ++ } ++ ++ return (ret); ++} ++ ++/* do_freebsd_pselect() must return target values and target errnos. */ ++static abi_long ++do_freebsd_pselect(int n, abi_ulong rfd_addr, abi_ulong wfd_addr, ++ abi_ulong efd_addr, abi_ulong ts_addr, abi_ulong set_addr) ++{ ++ fd_set rfds, wfds, efds; ++ fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; ++ sigset_t set, *set_ptr; ++ struct timespec ts, *ts_ptr; ++ void *p; ++ abi_long ret; ++ ++ ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); ++ if (ret) ++ return (ret); ++ ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n); ++ if (ret) ++ return (ret); ++ ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n); ++ if (ret) ++ return (ret); ++ ++ /* Unlike select(), pselect() uses struct timespec instead of timeval */ ++ if (ts_addr) { ++ if (target_to_host_timespec(&ts, ts_addr)) ++ return (-TARGET_EFAULT); ++ ts_ptr = &ts; ++ } else { ++ ts_ptr = NULL; ++ } ++ ++ if (set_addr) { ++ if (!(p = lock_user(VERIFY_READ, set_addr, ++ sizeof(target_sigset_t), 1))) ++ return (-TARGET_EFAULT); ++ target_to_host_sigset(&set, p); ++ unlock_user(p, set_addr, 0); ++ set_ptr = &set; ++ } else { ++ set_ptr = NULL; ++ } ++ ++ ret = get_errno(pselect(n, rfds_ptr, wfds_ptr, efds_ptr, ts_ptr, ++ set_ptr)); ++ ++ if (!is_error(ret)) { ++ if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) ++ return (-TARGET_EFAULT); ++ if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) ++ return (-TARGET_EFAULT); ++ if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) ++ return (-TARGET_EFAULT); ++ ++ if (ts_addr && host_to_target_timespec(ts_addr, &ts)) ++ return (-TARGET_EFAULT); ++ } ++ ++ return (ret); ++} ++ ++/* do_getsockopt() must return target values and target errnos. */ ++static abi_long ++do_getsockopt(int sockfd, int level, int optname, abi_ulong optval_addr, ++ abi_ulong optlen) ++{ ++ abi_long ret; ++ int len, val; ++ socklen_t lv; ++ ++ switch(level) { ++ case TARGET_SOL_SOCKET: ++ level = SOL_SOCKET; ++ switch (optname) { ++ ++ /* These don't just return a single integer */ ++ case TARGET_SO_LINGER: ++ case TARGET_SO_RCVTIMEO: ++ case TARGET_SO_SNDTIMEO: ++ case TARGET_SO_ACCEPTFILTER: ++ goto unimplemented; ++ ++ /* Options with 'int' argument. */ ++ case TARGET_SO_DEBUG: ++ optname = SO_DEBUG; ++ goto int_case; ++ ++ case TARGET_SO_REUSEADDR: ++ optname = SO_REUSEADDR; ++ goto int_case; ++ ++ case TARGET_SO_REUSEPORT: ++ optname = SO_REUSEPORT; ++ goto int_case; ++ ++ case TARGET_SO_TYPE: ++ optname = SO_TYPE; ++ goto int_case; ++ ++ case TARGET_SO_ERROR: ++ optname = SO_ERROR; ++ goto int_case; ++ ++ case TARGET_SO_DONTROUTE: ++ optname = SO_DONTROUTE; ++ goto int_case; ++ ++ case TARGET_SO_BROADCAST: ++ optname = SO_BROADCAST; ++ goto int_case; ++ ++ case TARGET_SO_SNDBUF: ++ optname = SO_SNDBUF; ++ goto int_case; ++ ++ case TARGET_SO_RCVBUF: ++ optname = SO_RCVBUF; ++ goto int_case; ++ ++ case TARGET_SO_KEEPALIVE: ++ optname = SO_KEEPALIVE; ++ goto int_case; ++ ++ case TARGET_SO_OOBINLINE: ++ optname = SO_OOBINLINE; ++ goto int_case; ++ ++ case TARGET_SO_TIMESTAMP: ++ optname = SO_TIMESTAMP; ++ goto int_case; ++ ++ case TARGET_SO_RCVLOWAT: ++ optname = SO_RCVLOWAT; ++ goto int_case; ++ ++ case TARGET_SO_LISTENINCQLEN: ++ optname = SO_LISTENINCQLEN; ++ goto int_case; ++ ++ default: ++int_case: ++ if (get_user_u32(len, optlen)) ++ return (-TARGET_EFAULT); ++ if (len < 0) ++ return (-TARGET_EINVAL); ++ lv = sizeof(lv); ++ ret = get_errno(getsockopt(sockfd, level, optname, ++ &val, &lv)); ++ if (ret < 0) ++ return (ret); ++ if (len > lv) ++ len = lv; ++ if (len == 4) { ++ if (put_user_u32(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ } else { ++ if (put_user_u8(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ } ++ if (put_user_u32(len, optlen)) ++ return (-TARGET_EFAULT); ++ break; ++ ++ } ++ break; ++ ++ default: ++unimplemented: ++ gemu_log("getsockopt level=%d optname=%d not yet supported\n", ++ level, optname); ++ ret = -TARGET_EOPNOTSUPP; ++ break; ++ } ++ return (ret); ++} ++ ++/* do_setsockopt() must return target values and target errnos. */ ++static abi_long ++do_setsockopt(int sockfd, int level, int optname, abi_ulong optval_addr, ++ socklen_t optlen) ++{ ++ int val; ++ abi_long ret; ++ ++ switch(level) { ++ case TARGET_SOL_SOCKET: ++ switch (optname) { ++ /* Options with 'int' argument. */ ++ case TARGET_SO_DEBUG: ++ optname = SO_DEBUG; ++ break; ++ ++ case TARGET_SO_REUSEADDR: ++ optname = SO_REUSEADDR; ++ break; ++ ++ case TARGET_SO_REUSEPORT: ++ optname = SO_REUSEADDR; ++ break; ++ ++ case TARGET_SO_KEEPALIVE: ++ optname = SO_KEEPALIVE; ++ break; ++ ++ case TARGET_SO_DONTROUTE: ++ optname = SO_DONTROUTE; ++ break; ++ ++ case TARGET_SO_LINGER: ++ optname = SO_LINGER; ++ break; ++ ++ case TARGET_SO_BROADCAST: ++ optname = SO_BROADCAST; ++ break; ++ ++ case TARGET_SO_OOBINLINE: ++ optname = SO_OOBINLINE; ++ break; ++ ++ case TARGET_SO_SNDBUF: ++ optname = SO_SNDBUF; ++ break; ++ ++ case TARGET_SO_RCVBUF: ++ optname = SO_RCVBUF; ++ break; ++ ++ case TARGET_SO_SNDLOWAT: ++ optname = SO_RCVLOWAT; ++ break; ++ ++ case TARGET_SO_RCVLOWAT: ++ optname = SO_RCVLOWAT; ++ break; ++ ++ case TARGET_SO_SNDTIMEO: ++ optname = SO_SNDTIMEO; ++ break; ++ ++ case TARGET_SO_RCVTIMEO: ++ optname = SO_RCVTIMEO; ++ break; ++ ++ case TARGET_SO_ACCEPTFILTER: ++ goto unimplemented; ++ ++ case TARGET_SO_NOSIGPIPE: ++ optname = SO_NOSIGPIPE; ++ break; ++ ++ case TARGET_SO_TIMESTAMP: ++ optname = SO_TIMESTAMP; ++ break; ++ ++ case TARGET_SO_BINTIME: ++ optname = SO_BINTIME; ++ break; ++ ++ case TARGET_SO_ERROR: ++ optname = SO_ERROR; ++ break; ++ ++ case TARGET_SO_SETFIB: ++ optname = SO_ERROR; ++ break; ++ ++ case TARGET_SO_USER_COOKIE: ++ optname = SO_USER_COOKIE; ++ break; ++ ++ default: ++ goto unimplemented; ++ } ++ if (optlen < sizeof(uint32_t)) ++ return (-TARGET_EINVAL); ++ if (get_user_u32(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, ++ sizeof(val))); ++ break; ++ default: ++unimplemented: ++ gemu_log("Unsupported setsockopt level=%d optname=%d\n", ++ level, optname); ++ ret = -TARGET_ENOPROTOOPT; ++ } ++ ++ return (ret); ++} ++ ++static inline abi_long ++target_to_host_sembuf(struct sembuf *host_sembuf, abi_ulong target_addr, ++ unsigned nsops) ++{ ++ struct target_sembuf *target_sembuf; ++ int i; ++ ++ target_sembuf = lock_user(VERIFY_READ, target_addr, ++ nsops * sizeof(struct target_sembuf), 1); ++ if (!target_sembuf) ++ return (-TARGET_EFAULT); ++ ++ for(i=0; isem_perm); ++ host_ip->cuid = tswapal(target_ip->cuid); ++ host_ip->cgid = tswapal(target_ip->cgid); ++ host_ip->uid = tswapal(target_ip->uid); ++ host_ip->gid = tswapal(target_ip->gid); ++ host_ip->mode = tswap16(target_ip->mode); ++ host_ip->seq = tswap16(target_ip->seq); ++ host_ip->key = tswapal(target_ip->key); ++ unlock_user_struct(target_sd, target_addr, 0); ++ ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_ipc_perm(abi_ulong target_addr, struct ipc_perm *host_ip) ++{ ++ struct target_ipc_perm *target_ip; ++ struct target_semid_ds *target_sd; ++ if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ target_ip = &(target_sd->sem_perm); ++ target_ip->cuid = tswapal(host_ip->cuid); ++ target_ip->cgid = tswapal(host_ip->cgid); ++ target_ip->uid = tswapal(host_ip->uid); ++ target_ip->gid = tswapal(host_ip->gid); ++ target_ip->mode = tswap16(host_ip->mode); ++ target_ip->seq = tswap16(host_ip->seq); ++ target_ip->key = tswapal(host_ip->key); ++ unlock_user_struct(target_sd, target_addr, 1); ++ return (0); ++} ++ ++static inline abi_long ++target_to_host_semid_ds(struct semid_ds *host_sd, abi_ulong target_addr) ++{ ++ struct target_semid_ds *target_sd; ++ ++ if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) ++ return (-TARGET_EFAULT); ++ if (target_to_host_ipc_perm(&(host_sd->sem_perm), target_addr)) ++ return (-TARGET_EFAULT); ++ /* sem_base is not used by kernel for IPC_STAT/IPC_SET */ ++ host_sd->sem_base = NULL; ++ host_sd->sem_nsems = tswapal(target_sd->sem_nsems); ++ host_sd->sem_otime = tswapal(target_sd->sem_otime); ++ host_sd->sem_ctime = tswapal(target_sd->sem_ctime); ++ unlock_user_struct(target_sd, target_addr, 0); ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_semid_ds(abi_ulong target_addr, struct semid_ds *host_sd) ++{ ++ struct target_semid_ds *target_sd; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm))) ++ return (-TARGET_EFAULT); ++ /* sem_base is not used by kernel for IPC_STAT/IPC_SET */ ++ target_sd->sem_nsems = tswapal(host_sd->sem_nsems); ++ target_sd->sem_otime = tswapal(host_sd->sem_otime); ++ target_sd->sem_ctime = tswapal(host_sd->sem_ctime); ++ unlock_user_struct(target_sd, target_addr, 1); ++ ++ return (0); ++} ++ ++static inline abi_long ++do_semctl(int semid, int semnum, int cmd, union target_semun target_su) ++{ ++ union semun arg; ++ struct semid_ds dsarg; ++ unsigned short *array = NULL; ++ abi_long ret = -TARGET_EINVAL; ++ abi_long err; ++ ++ cmd &= 0xff; ++ ++ switch( cmd ) { ++ case GETVAL: ++ case SETVAL: ++ arg.val = tswap32(target_su.val); ++ ret = get_errno(semctl(semid, semnum, cmd, arg)); ++ target_su.val = tswap32(arg.val); ++ break; ++ ++ case GETALL: ++ case SETALL: ++ err = target_to_host_semarray(semid, &array, target_su.array); ++ if (err) ++ return (err); ++ arg.array = array; ++ ret = get_errno(semctl(semid, semnum, cmd, arg)); ++ err = host_to_target_semarray(semid, target_su.array, &array); ++ if (err) ++ return (err); ++ break; ++ ++ case IPC_STAT: ++ case IPC_SET: ++ err = target_to_host_semid_ds(&dsarg, target_su.buf); ++ if (err) ++ return (err); ++ arg.buf = &dsarg; ++ ret = get_errno(semctl(semid, semnum, cmd, arg)); ++ err = host_to_target_semid_ds(target_su.buf, &dsarg); ++ if (err) ++ return (err); ++ break; ++ ++ case IPC_RMID: ++ case GETPID: ++ case GETNCNT: ++ case GETZCNT: ++ ret = get_errno(semctl(semid, semnum, cmd, NULL)); ++ break; ++ ++ default: ++ ret = -TARGET_EINVAL; ++ break; ++ } ++ return (ret); ++} ++ ++#define N_SHM_REGIONS 32 ++ ++static struct shm_regions { ++ abi_long start; ++ abi_long size; ++} shm_regions[N_SHM_REGIONS]; ++ ++static inline abi_ulong ++do_shmat(int shmid, abi_ulong shmaddr, int shmflg) ++{ ++ abi_long raddr; ++ void *host_raddr; ++ struct shmid_ds shm_info; ++ int i,ret; ++ ++ /* Find out the length of the shared memory segment. */ ++ ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); ++ if (is_error(ret)) { ++ /* Can't get the length */ ++ return (ret); ++ } ++ ++ mmap_lock(); ++ ++ if (shmaddr) { ++ host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg); ++ } else { ++ abi_ulong mmap_start; ++ ++ mmap_start = mmap_find_vma(0, shm_info.shm_segsz); ++ ++ if (mmap_start == -1) { ++ errno = ENOMEM; ++ host_raddr = (void *)-1; ++ } else { ++ host_raddr = shmat(shmid, g2h(mmap_start), ++ shmflg /* | SHM_REMAP */); ++ } ++ } ++ ++ if (host_raddr == (void *)-1) { ++ mmap_unlock(); ++ return get_errno((long)host_raddr); ++ } ++ raddr=h2g((unsigned long)host_raddr); ++ ++ page_set_flags(raddr, raddr + shm_info.shm_segsz, ++ PAGE_VALID | PAGE_READ | ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE)); ++ ++ for (i = 0; i < N_SHM_REGIONS; i++) { ++ if (shm_regions[i].start == 0) { ++ shm_regions[i].start = raddr; ++ shm_regions[i].size = shm_info.shm_segsz; ++ break; ++ } ++ } ++ ++ mmap_unlock(); ++ return (raddr); ++} ++ ++static inline abi_long ++do_shmdt(abi_ulong shmaddr) ++{ ++ int i; ++ ++ for (i = 0; i < N_SHM_REGIONS; ++i) { ++ if (shm_regions[i].start == shmaddr) { ++ shm_regions[i].start = 0; ++ page_set_flags(shmaddr, ++ shmaddr + shm_regions[i].size, 0); ++ break; ++ } ++ } ++ ++ return ( get_errno(shmdt(g2h(shmaddr))) ); ++} ++ ++static inline abi_long ++target_to_host_shmid_ds(struct shmid_ds *host_sd, abi_ulong target_addr) ++{ ++ struct target_shmid_ds *target_sd; ++ ++ if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) ++ return (-TARGET_EFAULT); ++ if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr)) ++ return (-TARGET_EFAULT); ++ __get_user(host_sd->shm_segsz, &target_sd->shm_segsz); ++ __get_user(host_sd->shm_lpid, &target_sd->shm_lpid); ++ __get_user(host_sd->shm_cpid, &target_sd->shm_cpid); ++ __get_user(host_sd->shm_nattch, &target_sd->shm_nattch); ++ __get_user(host_sd->shm_atime, &target_sd->shm_atime); ++ __get_user(host_sd->shm_dtime, &target_sd->shm_dtime); ++ __get_user(host_sd->shm_ctime, &target_sd->shm_ctime); ++ unlock_user_struct(target_sd, target_addr, 0); ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_shmid_ds(abi_ulong target_addr, struct shmid_ds *host_sd) ++{ ++ struct target_shmid_ds *target_sd; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm))) ++ return (-TARGET_EFAULT); ++ __put_user(host_sd->shm_segsz, &target_sd->shm_segsz); ++ __put_user(host_sd->shm_lpid, &target_sd->shm_lpid); ++ __put_user(host_sd->shm_cpid, &target_sd->shm_cpid); ++ __put_user(host_sd->shm_nattch, &target_sd->shm_nattch); ++ __put_user(host_sd->shm_atime, &target_sd->shm_atime); ++ __put_user(host_sd->shm_dtime, &target_sd->shm_dtime); ++ __put_user(host_sd->shm_ctime, &target_sd->shm_ctime); ++ unlock_user_struct(target_sd, target_addr, 1); ++ return (0); ++} ++ ++static inline abi_long ++do_shmctl(int shmid, int cmd, abi_long buff) ++{ ++ struct shmid_ds dsarg; ++ abi_long ret = -TARGET_EINVAL; ++ ++ cmd &= 0xff; ++ ++ switch(cmd) { ++ case IPC_STAT: ++ case IPC_SET: ++ if (target_to_host_shmid_ds(&dsarg, buff)) ++ return (-TARGET_EFAULT); ++ ret = get_errno(shmctl(shmid, cmd, &dsarg)); ++ if (host_to_target_shmid_ds(buff, &dsarg)) ++ return (-TARGET_EFAULT); ++ break; ++ ++ case IPC_RMID: ++ ret = get_errno(shmctl(shmid, cmd, NULL)); ++ break; ++ ++ default: ++ ret = -TARGET_EINVAL; ++ break; ++ } ++ ++ return (ret); ++} ++ ++static inline abi_long ++target_to_host_msqid_ds(struct msqid_ds *host_md, abi_ulong target_addr) ++{ ++ struct target_msqid_ds *target_md; ++ ++ if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) ++ return (-TARGET_EFAULT); ++ if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr)) ++ return (-TARGET_EFAULT); ++ ++ /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */ ++ host_md->msg_first = host_md->msg_last = NULL; ++ ++ host_md->msg_cbytes = tswapal(target_md->msg_cbytes); ++ host_md->msg_qnum = tswapal(target_md->msg_qnum); ++ host_md->msg_qbytes = tswapal(target_md->msg_qbytes); ++ host_md->msg_lspid = tswapal(target_md->msg_lspid); ++ host_md->msg_lrpid = tswapal(target_md->msg_lrpid); ++ host_md->msg_stime = tswapal(target_md->msg_stime); ++ host_md->msg_rtime = tswapal(target_md->msg_rtime); ++ host_md->msg_ctime = tswapal(target_md->msg_ctime); ++ unlock_user_struct(target_md, target_addr, 0); ++ ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_msqid_ds(abi_ulong target_addr, struct msqid_ds *host_md) ++{ ++ struct target_msqid_ds *target_md; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm))) ++ return (-TARGET_EFAULT); ++ ++ /* msg_first and msg_last are not used by IPC_SET/IPC_STAT in kernel. */ ++ target_md->msg_cbytes = tswapal(host_md->msg_cbytes); ++ target_md->msg_qnum = tswapal(host_md->msg_qnum); ++ target_md->msg_qbytes = tswapal(host_md->msg_qbytes); ++ target_md->msg_lspid = tswapal(host_md->msg_lspid); ++ target_md->msg_lrpid = tswapal(host_md->msg_lrpid); ++ target_md->msg_stime = tswapal(host_md->msg_stime); ++ target_md->msg_rtime = tswapal(host_md->msg_rtime); ++ target_md->msg_ctime = tswapal(host_md->msg_ctime); ++ unlock_user_struct(target_md, target_addr, 1); ++ ++ return (0); ++} ++ ++static inline abi_long ++do_msgctl(int msgid, int cmd, abi_long ptr) ++{ ++ struct msqid_ds dsarg; ++ abi_long ret = -TARGET_EINVAL; ++ ++ cmd &= 0xff; ++ ++ switch (cmd) { ++ case IPC_STAT: ++ case IPC_SET: ++ if (target_to_host_msqid_ds(&dsarg,ptr)) ++ return -TARGET_EFAULT; ++ ret = get_errno(msgctl(msgid, cmd, &dsarg)); ++ if (host_to_target_msqid_ds(ptr,&dsarg)) ++ return -TARGET_EFAULT; ++ break; ++ ++ case IPC_RMID: ++ ret = get_errno(msgctl(msgid, cmd, NULL)); ++ break; ++ ++ default: ++ ret = -TARGET_EINVAL; ++ break; ++ } ++ return (ret); ++} ++ ++static inline abi_long ++do_msgsnd(int msqid, abi_long msgp, unsigned int msgsz, int msgflg) ++{ ++ struct target_msgbuf *target_mb; ++ struct mymsg *host_mb; ++ abi_long ret = 0; ++ ++ if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) ++ return (-TARGET_EFAULT); ++ ++ host_mb = malloc(msgsz+sizeof(long)); ++ host_mb->mtype = (abi_long) tswapal(target_mb->mtype); ++ memcpy(host_mb->mtext, target_mb->mtext, msgsz); ++ ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg)); ++ free(host_mb); ++ unlock_user_struct(target_mb, msgp, 0); ++ ++ return (ret); ++} ++ ++static inline abi_long ++do_msgrcv(int msqid, abi_long msgp, unsigned int msgsz, abi_long msgtyp, ++ int msgflg) ++{ ++ struct target_msgbuf *target_mb; ++ char *target_mtext; ++ struct mymsg *host_mb; ++ abi_long ret = 0; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) ++ return (-TARGET_EFAULT); ++ ++ host_mb = g_malloc(msgsz+sizeof(long)); ++ ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg)); ++ if (ret > 0) { ++ abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); ++ target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ++ ret, 0); ++ if (!target_mtext) { ++ ret = -TARGET_EFAULT; ++ goto end; ++ } ++ memcpy(target_mb->mtext, host_mb->mtext, ret); ++ unlock_user(target_mtext, target_mtext_addr, ret); ++ } ++ target_mb->mtype = tswapal(host_mb->mtype); ++end: ++ if (target_mb) ++ unlock_user_struct(target_mb, msgp, 1); ++ g_free(host_mb); ++ return (ret); ++} ++ ++static void ++set_second_rval(CPUArchState *env, abi_ulong retval2) ++{ ++#if defined(TARGET_ALPHA) ++ ((CPUAlphaState *)env)->ir[IR_A4] = retval2; ++#elif defined(TARGET_ARM) ++ ((CPUARMState *)env)->regs[1] = retval2; ++#elif defined(TARGET_MIPS) ++ ((CPUMIPSState*)env)->active_tc.gpr[3] = retval2; ++#elif defined(TARGET_SH4) ++ ((CPUSH4State*)env)->gregs[1] = retval2; ++#elif defined(TARGET_X86_64) || defined(TARGET_I386) ++ ((CPUX86State*)env)->regs[R_EDX] = retval2; ++#elif defined(TARGET_SPARC64) || defined(TARGET_SPARC) ++ ((CPUSPARCState*)env)->regwptr[1] = retval2; ++#else ++#warning Arch not supported for returning multiple values from syscall. ++#endif ++} ++ ++/* ++ * do_fock() must return host values and target errnos (unlike most do_*() ++ * functions. ++ */ ++static int ++do_fork(CPUArchState *env, int num, int flags, int *fdp) ++{ ++ int ret, fd; ++ abi_ulong child_flag = 0; ++ ++ fork_start(); ++ switch(num) { ++ case TARGET_FREEBSD_NR_fork: ++ case TARGET_FREEBSD_NR_vfork: ++ ret = fork(); ++ break; ++ ++ case TARGET_FREEBSD_NR_rfork: ++ ret = rfork(flags); ++ break; ++ ++ case TARGET_FREEBSD_NR_pdfork: ++ ret = pdfork(&fd, flags); ++ break; ++ ++ default: ++ ret = -TARGET_ENOSYS; ++ break; ++ } ++ if (0 == ret) { ++ /* Child */ ++ child_flag = 1; ++ cpu_clone_regs(env, 0); ++ } else { ++ /* Parent */ ++ fork_end(0); ++ } ++ if (fdp != NULL) ++ *fdp = fd; ++ ++ /* ++ * The fork() syscall sets a child flag in 2nd return value: ++ * 0 for parent process, 1 for child process ++ */ ++ set_second_rval(env, child_flag); ++ ++ 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_. */ ++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; ++ struct stat st; ++ ++#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; ++ ++#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__ ++ case TARGET_FREEBSD_NR___sysctl: ++ ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); ++ break; ++#endif ++ case TARGET_FREEBSD_NR_sysarch: ++ ret = do_freebsd_sysarch(cpu_env, arg1, arg2); ++ break; ++ case TARGET_FREEBSD_NR_syscall: ++ case TARGET_FREEBSD_NR___syscall: ++ ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0); ++ 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; ++ ++ 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; ++ ++ case TARGET_FREEBSD_NR_nstat: ++ case TARGET_FREEBSD_NR_nfstat: ++ case TARGET_FREEBSD_NR_nlstat: ++ ret = unimplemented(num); ++ 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); ++ } ++ ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_nanosleep: ++ { ++ struct timespec req, rem; ++ ++ target_to_host_timespec(&req, arg1); ++ ret = get_errno(nanosleep(&req, &rem)); ++ if (is_error(ret) && arg2) ++ host_to_target_timespec(arg2, &rem); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_clock_gettime: ++ { ++ struct timespec ts; ++ ++ ret = get_errno(clock_gettime(arg1, &ts)); ++ if (!is_error(ret)) { ++ if (host_to_target_timespec(arg2, &ts)) ++ goto efault; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_clock_getres: ++ { ++ struct timespec ts; ++ ++ ret = get_errno(clock_getres(arg1, &ts)); ++ if (!is_error(ret)) { ++ if (host_to_target_timespec(arg2, &ts)) ++ goto efault; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_clock_settime: ++ { ++ struct timespec ts; ++ ++ if (target_to_host_timespec(&ts, arg2) != 0) ++ goto efault; ++ ret = get_errno(clock_settime(arg1, &ts)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_gettimeofday: ++ { ++ struct timeval tv; ++ struct timezone tz, *target_tz; ++ if (arg2 != 0) { ++ if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) ++ goto efault; ++ __get_user(tz.tz_minuteswest, ++ &target_tz->tz_minuteswest); ++ __get_user(tz.tz_dsttime, &target_tz->tz_dsttime); ++ unlock_user_struct(target_tz, arg2, 1); ++ } ++ ret = get_errno(gettimeofday(&tv, arg2 != 0 ? &tz : NULL)); ++ if (!is_error(ret)) { ++ if (fbsd_copy_to_user_timeval(&tv, arg1)) ++ goto efault; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_settimeofday: ++ { ++ struct timeval tv; ++ struct timezone tz, *target_tz; ++ ++ if (arg2 != 0) { ++ if (!lock_user_struct(VERIFY_READ, target_tz, arg2, 0)) ++ goto efault; ++ __get_user(tz.tz_minuteswest, ++ &target_tz->tz_minuteswest); ++ __get_user(tz.tz_dsttime, &target_tz->tz_dsttime); ++ unlock_user_struct(target_tz, arg2, 1); ++ } ++ if (copy_from_user_timeval(&tv, arg1)) ++ goto efault; ++ ret = get_errno(settimeofday(&tv, arg2 != 0 ? & tz : NULL)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_ktimer_create: ++ case TARGET_FREEBSD_NR_ktimer_delete: ++ case TARGET_FREEBSD_NR_ktimer_settime: ++ case TARGET_FREEBSD_NR_ktimer_gettime: ++ case TARGET_FREEBSD_NR_ktimer_getoverrun: ++ case TARGET_FREEBSD_NR_minherit: ++ ret = unimplemented(num); ++ break; ++ ++ case TARGET_FREEBSD_NR_kqueue: ++ ret = get_errno(kqueue()); ++ break; ++ ++#ifdef __FreeBSD__ ++ case TARGET_FREEBSD_NR_kevent: ++ { ++ struct kevent *changelist = NULL, *eventlist = NULL; ++ struct target_kevent *target_changelist, *target_eventlist; ++ struct timespec ts; ++ int i; ++ ++ if (arg3 != 0) { ++ if (!(target_changelist = lock_user(VERIFY_READ, arg2, ++ sizeof(struct target_kevent) * arg3, 1))) ++ goto efault; ++ changelist = alloca(sizeof(struct kevent) * arg3); ++ ++ for (i = 0; i < arg3; i++) { ++ __get_user(changelist[i].ident, &target_changelist[i].ident); ++ __get_user(changelist[i].filter, &target_changelist[i].filter); ++ __get_user(changelist[i].flags, &target_changelist[i].flags); ++ __get_user(changelist[i].fflags, &target_changelist[i].fflags); ++ __get_user(changelist[i].data, &target_changelist[i].data); ++ /* XXX: This is broken when running a 64bits target on a 32bits host */ ++ /* __get_user(changelist[i].udata, &target_changelist[i].udata); */ ++#if TARGET_ABI_BITS == 32 ++ changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata; ++ tswap32s((uint32_t *)&changelist[i].udata); ++#else ++ changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata; ++ tswap64s((uint64_t *)&changelist[i].udata); ++#endif ++ } ++ unlock_user(target_changelist, arg2, 0); ++ } ++ ++ if (arg5 != 0) ++ eventlist = alloca(sizeof(struct kevent) * arg5); ++ if (arg6 != 0) ++ if (target_to_host_timespec(&ts, arg6)) ++ goto efault; ++ ret = get_errno(kevent(arg1, changelist, arg3, eventlist, arg5, ++ arg6 != 0 ? &ts : NULL)); ++ if (!is_error(ret)) { ++ if (!(target_eventlist = lock_user(VERIFY_WRITE, arg4, ++ sizeof(struct target_kevent) * arg5, 0))) ++ goto efault; ++ for (i = 0; i < arg5; i++) { ++ __put_user(eventlist[i].ident, &target_eventlist[i].ident); ++ __put_user(eventlist[i].filter, &target_eventlist[i].filter); ++ __put_user(eventlist[i].flags, &target_eventlist[i].flags); ++ __put_user(eventlist[i].fflags, &target_eventlist[i].fflags); ++ __put_user(eventlist[i].data, &target_eventlist[i].data); ++ /* __put_user(eventlist[i].udata, &target_eventlist[i].udata); */ ++#if TARGET_ABI_BITS == 32 ++ tswap32s((uint32_t *)&eventlist[i].data); ++ target_eventlist[i].data = (uintptr_t)eventlist[i].data; ++#else ++ tswap64s((uint64_t *)&eventlist[i].data); ++ target_eventlist[i].data = (uintptr_t)eventlist[i].data; ++#endif ++ } ++ unlock_user(target_eventlist, arg4, sizeof(struct target_kevent) * arg5); ++ ++ ++ } ++ } ++ break; ++#endif ++ ++ case TARGET_FREEBSD_NR_execve: ++ { ++ char **argp, **envp; ++ int argc, envc; ++ abi_ulong gp; ++ abi_ulong guest_argp; ++ abi_ulong guest_envp; ++ abi_ulong addr; ++ char **q; ++ int total_size = 0; ++ ++ argc = 0; ++ guest_argp = arg2; ++ for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { ++ if (get_user_ual(addr, gp)) ++ goto efault; ++ if (!addr) ++ break; ++ argc++; ++ } ++ envc = 0; ++ guest_envp = arg3; ++ for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { ++ if (get_user_ual(addr, gp)) ++ goto efault; ++ if (!addr) ++ break; ++ envc++; ++ } ++ ++ argp = alloca((argc + 1) * sizeof(void *)); ++ envp = alloca((envc + 1) * sizeof(void *)); ++ ++ for (gp = guest_argp, q = argp; gp; ++ gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp)) ++ goto execve_efault; ++ if (!addr) ++ break; ++ if (!(*q = lock_user_string(addr))) ++ goto execve_efault; ++ total_size += strlen(*q) + 1; ++ } ++ *q = NULL; ++ ++ for (gp = guest_envp, q = envp; gp; ++ gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp)) ++ goto execve_efault; ++ if (!addr) ++ break; ++ if (!(*q = lock_user_string(addr))) ++ goto execve_efault; ++ total_size += strlen(*q) + 1; ++ } ++ *q = NULL; ++ ++ /* This case will not be caught by the host's execve() if its ++ page size is bigger than the target's. */ ++ if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { ++ ret = -TARGET_E2BIG; ++ goto execve_end; ++ } ++ if (!(p = lock_user_string(arg1))) ++ goto execve_efault; ++ ret = get_errno(execve(p, argp, envp)); ++ unlock_user(p, arg1, 0); ++ ++ goto execve_end; ++ ++ execve_efault: ++ ret = -TARGET_EFAULT; ++ ++ execve_end: ++ for (gp = guest_argp, q = argp; *q; ++ gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp) ++ || !addr) ++ break; ++ unlock_user(*q, addr, 0); ++ } ++ for (gp = guest_envp, q = envp; *q; ++ gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp) ++ || !addr) ++ break; ++ unlock_user(*q, addr, 0); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_pipe: ++ { ++ int host_pipe[2]; ++ int host_ret = pipe(host_pipe); ++ ++ if (!is_error(host_ret)) { ++ set_second_rval(cpu_env, host_pipe[1]); ++ ret = host_pipe[0]; ++ } else ++ ret = get_errno(host_ret); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_lseek: ++ { ++#if defined(TARGET_MIPS) && TARGET_ABI_BITS == 32 ++ /* 32-bit MIPS uses two 32 registers for 64 bit arguments */ ++ int64_t res = lseek(arg1, target_offset64(arg2, arg3), arg4); ++ ++ if (res == -1) { ++ ret = get_errno(res); ++ } else { ++ ret = res & 0xFFFFFFFF; ++ ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = ++ (res >> 32) & 0xFFFFFFFF; ++ } ++#else ++ ret = get_errno(lseek(arg1, arg2, arg3)); ++#endif ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_select: ++ ret = do_freebsd_select(arg1, arg2, arg3, arg4, arg5); ++ break; ++ ++ case TARGET_FREEBSD_NR_pselect: ++ ret = do_freebsd_pselect(arg1, arg2, arg3, arg4, arg5, arg6); ++ break; ++ ++ case TARGET_FREEBSD_NR_poll: ++ { ++ nfds_t i, nfds = arg2; ++ int timeout = arg3; ++ struct pollfd *pfd; ++ struct target_pollfd *target_pfd = lock_user(VERIFY_WRITE, arg1, ++ sizeof(struct target_pollfd) * nfds, 1); ++ ++ if (!target_pfd) ++ goto efault; ++ ++ pfd = alloca(sizeof(struct pollfd) * nfds); ++ for(i = 0; i < nfds; i++) { ++ pfd[i].fd = tswap32(target_pfd[i].fd); ++ pfd[i].events = tswap16(target_pfd[i].events); ++ } ++ ret = get_errno(poll(pfd, nfds, timeout)); ++ ++ if (!is_error(ret)) { ++ for(i = 0; i < nfds; i++) { ++ target_pfd[i].revents = tswap16(pfd[i].revents); ++ } ++ } ++ unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * ++ nfds); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_openbsd_poll: ++ ret = unimplemented(num); ++ break; ++ ++ case TARGET_FREEBSD_NR_setrlimit: ++ { ++ int resource = target_to_host_resource(arg1); ++ struct target_rlimit *target_rlim; ++ struct rlimit rlim; ++ ++ if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) ++ goto efault; ++ rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur); ++ rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max); ++ unlock_user_struct(target_rlim, arg2, 0); ++ ret = get_errno(setrlimit(resource, &rlim)); ++ } ++ break; ++ ++ ++ case TARGET_FREEBSD_NR_getrlimit: ++ { ++ int resource = target_to_host_resource(arg1); ++ struct target_rlimit *target_rlim; ++ struct rlimit rlim; ++ ++ ret = get_errno(getrlimit(resource, &rlim)); ++ if (!is_error(ret)) { ++ if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, ++ 0)) ++ goto efault; ++ target_rlim->rlim_cur = ++ host_to_target_rlim(rlim.rlim_cur); ++ target_rlim->rlim_max = ++ host_to_target_rlim(rlim.rlim_max); ++ unlock_user_struct(target_rlim, arg2, 1); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_setitimer: ++ { ++ struct itimerval value, ovalue, *pvalue; ++ ++ if (arg2) { ++ pvalue = &value; ++ if (copy_from_user_timeval(&pvalue->it_interval, ++ arg2) || copy_from_user_timeval( ++ &pvalue->it_value, arg2 + ++ sizeof(struct target_timeval))) ++ goto efault; ++ } else { ++ pvalue = NULL; ++ } ++ 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, ++ arg3 + sizeof(struct target_timeval))) ++ goto efault; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_getitimer: ++ { ++ struct itimerval value; ++ ++ 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, ++ arg2 + sizeof(struct target_timeval))) ++ goto efault; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_utimes: ++ { ++ struct timeval *tvp, tv[2]; ++ ++ if (arg2) { ++ if (copy_from_user_timeval(&tv[0], arg2) ++ || copy_from_user_timeval(&tv[1], ++ arg2 + sizeof(struct target_timeval))) ++ ++ goto efault; ++ tvp = tv; ++ } else { ++ tvp = NULL; ++ } ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(utimes(p, tvp)); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_lutimes: ++ { ++ struct timeval *tvp, tv[2]; ++ ++ if (arg2) { ++ if (copy_from_user_timeval(&tv[0], arg2) ++ || copy_from_user_timeval(&tv[1], ++ arg2 + sizeof(struct target_timeval))) ++ ++ goto efault; ++ tvp = tv; ++ } else { ++ tvp = NULL; ++ } ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(lutimes(p, tvp)); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_futimes: ++ { ++ struct timeval *tvp, tv[2]; ++ ++ if (arg2) { ++ if (copy_from_user_timeval(&tv[0], arg2) ++ || copy_from_user_timeval(&tv[1], ++ arg2 + sizeof(struct target_timeval))) ++ goto efault; ++ tvp = tv; ++ } else { ++ tvp = NULL; ++ } ++ ret = get_errno(futimes(arg1, tvp)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_futimesat: ++ { ++ struct timeval *tvp, tv[2]; ++ ++ if (arg3) { ++ if (copy_from_user_timeval(&tv[0], arg3) ++ || copy_from_user_timeval(&tv[1], ++ arg3 + sizeof(struct target_timeval))) ++ goto efault; ++ tvp = tv; ++ } else { ++ tvp = NULL; ++ } ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(futimesat(arg1, path(p), tvp)); ++ unlock_user(p, arg2, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_access: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(access(path(p), arg2)); ++ unlock_user(p, arg1, 0); ++ ++ case TARGET_FREEBSD_NR_eaccess: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(eaccess(path(p), arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_faccessat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(faccessat(arg1, p, arg3, arg4)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_chdir: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(chdir(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fchdir: ++ ret = get_errno(fchdir(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_rename: ++ { ++ void *p2; ++ ++ p = lock_user_string(arg1); ++ p2 = lock_user_string(arg2); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(rename(p, p2)); ++ unlock_user(p2, arg2, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_renameat: ++ { ++ void *p2; ++ ++ p = lock_user_string(arg2); ++ p2 = lock_user_string(arg4); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(renameat(arg1, p, arg3, p2)); ++ unlock_user(p2, arg4, 0); ++ unlock_user(p, arg2, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_link: ++ { ++ void * p2; ++ ++ p = lock_user_string(arg1); ++ p2 = lock_user_string(arg2); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(link(p, p2)); ++ unlock_user(p2, arg2, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_linkat: ++ { ++ void * p2 = NULL; ++ ++ if (!arg2 || !arg4) ++ goto efault; ++ ++ p = lock_user_string(arg2); ++ p2 = lock_user_string(arg4); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(linkat(arg1, p, arg3, p2, arg5)); ++ unlock_user(p, arg2, 0); ++ unlock_user(p2, arg4, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_unlink: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(unlink(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_unlinkat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(unlinkat(arg1, p, arg3)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_mkdir: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(mkdir(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_mkdirat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(mkdirat(arg1, p, arg3)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_rmdir: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(rmdir(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR___getcwd: ++ if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) ++ goto efault; ++ ret = get_errno(__getcwd(p, arg2)); ++ unlock_user(p, arg1, ret); ++ break; ++ ++ case TARGET_FREEBSD_NR_dup: ++ ret = get_errno(dup(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_dup2: ++ ret = get_errno(dup2(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_truncate: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (regpairs_aligned(cpu_env)) { ++ arg2 = arg3; ++ arg3 = arg4; ++ } ++ ret = get_errno(truncate(p, target_offset64(arg2, arg3))); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_ftruncate: ++ if (regpairs_aligned(cpu_env)) { ++ arg2 = arg3; ++ arg3 = arg4; ++ } ++ ret = get_errno(ftruncate(arg1, target_offset64(arg2, arg3))); ++ break; ++ ++ case TARGET_FREEBSD_NR_acct: ++ if (arg1 == 0) { ++ ret = get_errno(acct(NULL)); ++ } else { ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(acct(path(p))); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sync: ++ sync(); ++ ret = 0; ++ break; ++ ++ case TARGET_FREEBSD_NR_mount: ++ { ++ void *p2; ++ ++ /* We need to look at the data field. */ ++ p = lock_user_string(arg1); /* type */ ++ p2 = lock_user_string(arg2); /* dir */ ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else { ++ /* ++ * XXX arg5 should be locked, but it isn't clear ++ * how to do that since it's it may be not be a ++ * NULL-terminated string. ++ */ ++ if ( ! arg5 ) ++ ret = get_errno(mount(p, p2, arg3, NULL)); ++ else ++ ret = get_errno(mount(p, p2, arg3, g2h(arg5))); ++ } ++ unlock_user(p, arg1, 0); ++ unlock_user(p2, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_unmount: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(unmount(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_nmount: ++ { ++ int count = arg2; ++ struct iovec *vec; ++ ++ vec = alloca(count * sizeof(struct iovec)); ++ if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) ++ goto efault; ++ ret = get_errno(nmount(vec, count, arg3)); ++ unlock_iovec(vec, arg2, count, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_symlink: ++ { ++ void *p2; ++ ++ p = lock_user_string(arg1); ++ p2 = lock_user_string(arg2); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(symlink(p, p2)); ++ unlock_user(p2, arg2, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_symlinkat: ++ { ++ void *p2; ++ ++ p = lock_user_string(arg1); ++ p2 = lock_user_string(arg3); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(symlinkat(p, arg2, p2)); ++ unlock_user(p2, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_readlink: ++ { ++ void *p2; ++ ++ p = lock_user_string(arg1); ++ p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(readlink(path(p), p2, arg3)); ++ unlock_user(p2, arg2, ret); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_readlinkat: ++ { ++ void *p2; ++ p = lock_user_string(arg2); ++ p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); ++ ++ if (!p || !p2) ++ ret = -TARGET_EFAULT; ++ else ++ ret = get_errno(readlinkat(arg1, path(p), p2, arg4)); ++ unlock_user(p2, arg3, ret); ++ unlock_user(p, arg2, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_chmod: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(chmod(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fchmod: ++ ret = get_errno(fchmod(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_lchmod: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(lchmod(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fchmodat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(fchmodat(arg1, p, arg3, arg4)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_mknod: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(mknod(p, arg2, arg3)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_mknodat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(mknodat(arg1, p, arg3, arg4)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_chown: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(chown(p, arg2, arg3)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fchown: ++ ret = get_errno(fchown(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_lchown: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(lchown(p, arg2, arg3)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fchownat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(fchownat(arg1, p, arg3, arg4, arg5)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_chflags: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(chflags(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_lchflags: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(lchflags(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fchflags: ++ ret = get_errno(fchflags(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_getgroups: ++ { ++ int gidsetsize = arg1; ++ uint32_t *target_grouplist; ++ gid_t *grouplist; ++ int i; ++ ++ grouplist = alloca(gidsetsize * sizeof(gid_t)); ++ ret = get_errno(getgroups(gidsetsize, grouplist)); ++ if (gidsetsize == 0) ++ break; ++ if (!is_error(ret)) { ++ target_grouplist = lock_user(VERIFY_WRITE, arg2, ++ gidsetsize * 2, 0); ++ if (!target_grouplist) ++ goto efault; ++ for (i = 0;i < ret; i++) ++ target_grouplist[i] = tswap32(grouplist[i]); ++ unlock_user(target_grouplist, arg2, gidsetsize * 2); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_setgroups: ++ { ++ int gidsetsize = arg1; ++ uint32_t *target_grouplist; ++ gid_t *grouplist; ++ int i; ++ ++ grouplist = alloca(gidsetsize * sizeof(gid_t)); ++ target_grouplist = lock_user(VERIFY_READ, arg2, ++ gidsetsize * 2, 1); ++ if (!target_grouplist) { ++ ret = -TARGET_EFAULT; ++ goto fail; ++ } ++ for(i = 0;i < gidsetsize; i++) ++ grouplist[i] = tswap32(target_grouplist[i]); ++ unlock_user(target_grouplist, arg2, 0); ++ ret = get_errno(setgroups(gidsetsize, grouplist)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_umask: ++ ret = get_errno(umask(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_fcntl: ++ { ++ int host_cmd; ++ struct flock fl; ++ struct target_flock *target_fl; ++ ++ host_cmd = target_to_host_fcntl_cmd(arg2); ++ if (-TARGET_EINVAL == host_cmd) { ++ ret = host_cmd; ++ break; ++ } ++ ++ switch(arg2) { ++ case TARGET_F_GETLK: ++ if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) ++ return (-TARGET_EFAULT); ++ fl.l_type = tswap16(target_fl->l_type); ++ fl.l_whence = tswap16(target_fl->l_whence); ++ fl.l_start = tswapal(target_fl->l_start); ++ fl.l_len = tswapal(target_fl->l_len); ++ fl.l_pid = tswap32(target_fl->l_pid); ++ fl.l_sysid = tswap32(target_fl->l_sysid); ++ unlock_user_struct(target_fl, arg3, 0); ++ ret = get_errno(fcntl(arg1, host_cmd, &fl)); ++ if (0 == ret) { ++ if (!lock_user_struct(VERIFY_WRITE, target_fl, ++ arg3, 0)) ++ return (-TARGET_EFAULT); ++ target_fl->l_type = tswap16(fl.l_type); ++ target_fl->l_whence = tswap16(fl.l_whence); ++ target_fl->l_start = tswapal(fl.l_start); ++ target_fl->l_len = tswapal(fl.l_len); ++ target_fl->l_pid = tswap32(fl.l_pid); ++ target_fl->l_sysid = tswap32(fl.l_sysid); ++ unlock_user_struct(target_fl, arg3, 1); ++ } ++ break; ++ ++ case TARGET_F_SETLK: ++ case TARGET_F_SETLKW: ++ if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) ++ return (-TARGET_EFAULT); ++ fl.l_type = tswap16(target_fl->l_type); ++ fl.l_whence = tswap16(target_fl->l_whence); ++ fl.l_start = tswapal(target_fl->l_start); ++ fl.l_len = tswapal(target_fl->l_len); ++ fl.l_pid = tswap32(target_fl->l_pid); ++ fl.l_sysid = tswap32(target_fl->l_sysid); ++ unlock_user_struct(target_fl, arg3, 0); ++ ret = get_errno(fcntl(arg1, host_cmd, &fl)); ++ break; ++ ++ case TARGET_F_DUPFD: ++ case TARGET_F_DUP2FD: ++ case TARGET_F_GETOWN: ++ case TARGET_F_SETOWN: ++ case TARGET_F_GETFD: ++ case TARGET_F_SETFD: ++ case TARGET_F_GETFL: ++ case TARGET_F_SETFL: ++ case TARGET_F_READAHEAD: ++ case TARGET_F_RDAHEAD: ++ default: ++ ret = get_errno(fcntl(arg1, host_cmd, arg3)); ++ break; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_getdents: ++ { ++ struct dirent *dirp; ++ int32_t nbytes = arg3; ++ ++ if (!(dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0))) ++ goto efault; ++ ret = get_errno(getdents(arg1, (char *)dirp, nbytes)); ++ if (!is_error(ret)) { ++ struct dirent *de; ++ int len = ret; ++ int reclen; ++ ++ de = dirp; ++ while (len > 0) { ++ reclen = de->d_reclen; ++ if (reclen > len) ++ break; ++ de->d_reclen = tswap16(reclen); ++ len -= reclen; ++ } ++ } ++ unlock_user(dirp, arg2, ret); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_getdirentries: ++ { ++ struct dirent *dirp; ++ int32_t nbytes = arg3; ++ long basep; ++ ++ if (!(dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0))) ++ goto efault; ++ ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, ++ &basep)); ++ if (!is_error(ret)) { ++ struct dirent *de; ++ int len = ret; ++ int reclen; ++ ++ de = dirp; ++ while (len > 0) { ++ reclen = de->d_reclen; ++ if (reclen > len) ++ break; ++ de->d_reclen = tswap16(reclen); ++ len -= reclen; ++ } ++ } ++ unlock_user(dirp, arg2, ret); ++ if (arg4) ++ if (put_user(nbytes, arg4, abi_ulong)) ++ ret = -TARGET_EFAULT; ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_chroot: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(chroot(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_flock: ++ ret = get_errno(flock(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_mkfifo: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(mkfifo(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_mkfifoat: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = get_errno(mkfifoat(arg1, p, arg2)); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_pathconf: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(pathconf(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_lpathconf: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(lpathconf(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_fpathconf: ++ ret = get_errno(fpathconf(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_undelete: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(undelete(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ ++ case TARGET_FREEBSD_NR___acl_get_file: ++ case TARGET_FREEBSD_NR___acl_set_file: ++ case TARGET_FREEBSD_NR___acl_get_fd: ++ case TARGET_FREEBSD_NR___acl_set_fd: ++ case TARGET_FREEBSD_NR___acl_delete_file: ++ case TARGET_FREEBSD_NR___acl_delete_fd: ++ case TARGET_FREEBSD_NR___acl_aclcheck_file: ++ case TARGET_FREEBSD_NR___acl_aclcheck_fd: ++ case TARGET_FREEBSD_NR___acl_get_link: ++ case TARGET_FREEBSD_NR___acl_set_link: ++ case TARGET_FREEBSD_NR___acl_delete_link: ++ case TARGET_FREEBSD_NR___acl_aclcheck_link: ++ case TARGET_FREEBSD_NR_extattrctl: ++ case TARGET_FREEBSD_NR_extattr_set_file: ++ case TARGET_FREEBSD_NR_extattr_get_file: ++ case TARGET_FREEBSD_NR_extattr_delete_file: ++ case TARGET_FREEBSD_NR_extattr_set_fd: ++ case TARGET_FREEBSD_NR_extattr_get_fd: ++ case TARGET_FREEBSD_NR_extattr_delete_fd: ++ case TARGET_FREEBSD_NR_extattr_get_link: ++ case TARGET_FREEBSD_NR_extattr_set_link: ++ case TARGET_FREEBSD_NR_extattr_delete_link: ++ case TARGET_FREEBSD_NR_extattr_list_fd: ++ case TARGET_FREEBSD_NR_extattr_list_file: ++ case TARGET_FREEBSD_NR_extattr_list_link: ++ ret = unimplemented(num); ++ break; ++ ++ case TARGET_FREEBSD_NR_setlogin: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(setlogin(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_getlogin: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(_getlogin(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_setloginclass: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(setloginclass(p)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_getloginclass: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(getloginclass(p, arg2)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_getrusage: ++ { ++ struct rusage rusage; ++ ret = get_errno(getrusage(arg1, &rusage)); ++ if (!is_error(ret)) ++ host_to_target_rusage(arg2, &rusage); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_wait4: ++ { ++ int status; ++ abi_long status_ptr = arg2; ++ struct rusage rusage, *rusage_ptr; ++ abi_ulong target_rusage = arg4; ++ ++ if (target_rusage) ++ rusage_ptr = &rusage; ++ else ++ rusage_ptr = NULL; ++ ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); ++ if (!is_error(ret)) { ++ status = host_to_target_waitstatus(status); ++ if (put_user_s32(status, status_ptr)) ++ goto efault; ++ if (target_rusage) ++ host_to_target_rusage(target_rusage, &rusage); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_accept: ++ ret = do_accept(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_bind: ++ ret = do_bind(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_connect: ++ ret = do_connect(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_getpeername: ++ ret = do_getpeername(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_getsockname: ++ ret = do_getsockname(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_getsockopt: ++ ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5); ++ break; ++ ++ case TARGET_FREEBSD_NR_setsockopt: ++ ret = do_setsockopt(arg1, arg2, arg3, arg4, arg5); ++ break; ++ ++ case TARGET_FREEBSD_NR_listen: ++ ret = get_errno(listen(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_recvfrom: ++ ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6); ++ break; ++ ++ case TARGET_FREEBSD_NR_recvmsg: ++ ret = do_sendrecvmsg(arg1, arg2, arg3, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_sendmsg: ++ ret = do_sendrecvmsg(arg1, arg2, arg3, 1); ++ break; ++ ++ case TARGET_FREEBSD_NR_sendto: ++ ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6); ++ break; ++ ++ case TARGET_FREEBSD_NR_socket: ++ ret = get_errno(socket(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_socketpair: ++ ret = do_socketpair(arg1, arg2, arg3, arg4); ++ break; ++ ++ case TARGET_FREEBSD_NR_getpriority: ++ /* ++ * Note that negative values are valid for getpriority, so we must ++ * differentiate based on errno settings. ++ */ ++ errno = 0; ++ ret = getpriority(arg1, arg2); ++ if (ret == -1 && errno != 0) { ++ ret = -host_to_target_errno(errno); ++ break; ++ } ++ /* Return value is a biased priority to avoid negative numbers. */ ++ ret = 20 - ret; ++ break; ++ ++ case TARGET_FREEBSD_NR_setpriority: ++ ret = get_errno(setpriority(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_semget: ++ ret = get_errno(semget(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_semop: ++ ret = get_errno(do_semop(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR___semctl: ++ ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4); ++ break; ++ ++ case TARGET_FREEBSD_NR_msgctl: ++ ret = do_msgctl(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_msgrcv: ++ ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5); ++ break; ++ ++ case TARGET_FREEBSD_NR_msgsnd: ++ ret = do_msgsnd(arg1, arg2, arg3, arg4); ++ break; ++ ++ case TARGET_FREEBSD_NR_shmget: ++ ret = get_errno(shmget(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_shmctl: ++ ret = do_shmctl(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_shmat: ++ ret = do_shmat(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_shmdt: ++ ret = do_shmdt(arg1); ++ break; ++ ++ case TARGET_FREEBSD_NR_shm_open: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(shm_open(path(p), ++ target_to_host_bitmask(arg2, fcntl_flags_tbl), ++ arg3)); ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_shm_unlink: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ret = get_errno(shm_unlink(p)); ++ break; ++ ++ case TARGET_FREEBSD_NR_getpid: ++ ret = get_errno(getpid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_getppid: ++ ret = get_errno(getppid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_getuid: ++ ret = get_errno(getuid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_geteuid: ++ ret = get_errno(geteuid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_getgid: ++ ret = get_errno(getgid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_getegid: ++ ret = get_errno(getegid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_setuid: ++ ret = get_errno(setuid(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_setgid: ++ ret = get_errno(setgid(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_setegid: ++ ret = get_errno(setegid(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_seteuid: ++ ret = get_errno(setegid(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_getpgrp: ++ ret = get_errno(getpgrp()); ++ break; ++ ++#ifdef TARGET_FREEBSD_NR_setpgrp ++ case TARGET_FREEBSD_NR_setpgrp: ++ ret = get_errno(setpgrp(arg1, arg2)); ++ break; ++#endif ++ ++ case TARGET_FREEBSD_NR_setreuid: ++ ret = get_errno(setreuid(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_setregid: ++ ret = get_errno(setregid(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR_setresuid: ++ ret = get_errno(setresuid(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_setresgid: ++ ret = get_errno(setresgid(arg1, arg2, arg3)); ++ break; ++ ++ case TARGET_FREEBSD_NR_getresuid: ++ case TARGET_FREEBSD_NR_getresgid: ++ ret = unimplemented(num); ++ break; ++ ++ case TARGET_FREEBSD_NR_setsid: ++ ret = get_errno(setsid()); ++ break; ++ ++ case TARGET_FREEBSD_NR_getsid: ++ ret = get_errno(getsid(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_setfib: ++ ret = get_errno(setfib(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR___setugid: ++ ret = get_errno(__setugid(arg1)); ++ break; ++ ++ case TARGET_FREEBSD_NR_issetugid: ++ ret = get_errno(issetugid()); ++ break; ++ ++#ifdef TARGET_FREEBSD_NR_wait ++ case TARGET_FREEBSD_NR_wait: ++ ret = get_errno(wait()); ++ break; ++#endif ++ ++ case TARGET_FREEBSD_NR_fork: ++ ret = get_errno(do_fork(cpu_env, num, 0, NULL)); ++ break; ++ ++ case TARGET_FREEBSD_NR_rfork: ++ ret = get_errno(do_fork(cpu_env, num, arg1, NULL)); ++ break; ++ ++ case TARGET_FREEBSD_NR_vfork: ++ ret = get_errno(do_fork(cpu_env, num, 0, NULL)); ++ break; ++ ++ case TARGET_FREEBSD_NR_pdfork: ++ { ++ int pd; ++ ++ ret = get_errno(do_fork(cpu_env, num, arg2, &pd)); ++ if (put_user_s32(pd, arg1)) ++ goto efault; ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_kill: ++ ret = get_errno(kill(arg1, target_to_host_signal(arg2))); ++ break; ++ ++#ifdef TARGET_FREEBSD_NR_killpg ++ case TARGET_FREEBSD_NR_killpg: ++ ret = get_errno(killpg(arg1, target_to_host_signal(arg2))); ++ break; ++#endif ++ ++ case TARGET_FREEBSD_NR_sigaction: ++ { ++ struct target_sigaction *old_act, act, oact, *pact; ++ ++ if (arg2) { ++ if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) ++ goto efault; ++ act._sa_handler = old_act->_sa_handler; ++ act.sa_flags = old_act->sa_flags; ++ memcpy(&act.sa_mask, &old_act->sa_mask, ++ sizeof(target_sigset_t)); ++ unlock_user_struct(old_act, arg2, 0); ++ pact = &act; ++ } else { ++ pact = NULL; ++ } ++ ret = get_errno(do_sigaction(arg1, pact, &oact)); ++ if (!is_error(ret) && arg3) { ++ if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) ++ goto efault; ++ old_act->_sa_handler = oact._sa_handler; ++ old_act->sa_flags = oact.sa_flags; ++ memcpy(&old_act->sa_mask, &oact.sa_mask, ++ sizeof(target_sigset_t)); ++ unlock_user_struct(old_act, arg3, 1); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigprocmask: ++ { ++ sigset_t set, oldset, *set_ptr; ++ int how; ++ ++ if (arg2) { ++ switch (arg1) { ++ case TARGET_SIG_BLOCK: ++ how = SIG_BLOCK; ++ break; ++ ++ case TARGET_SIG_UNBLOCK: ++ how = SIG_UNBLOCK; ++ break; ++ ++ case TARGET_SIG_SETMASK: ++ how = SIG_SETMASK; ++ break; ++ ++ default: ++ ret = -TARGET_EINVAL; ++ goto fail; ++ } ++ if (!(p = lock_user(VERIFY_READ, arg2, ++ sizeof(target_sigset_t), 1))) ++ goto efault; ++ target_to_host_sigset(&set, p); ++ unlock_user(p, arg2, 0); ++ set_ptr = &set; ++ } else { ++ how = 0; ++ set_ptr = NULL; ++ } ++ ret = get_errno(sigprocmask(how, set_ptr, &oldset)); ++ if (!is_error(ret) && arg3) { ++ if (!(p = lock_user(VERIFY_WRITE, arg3, ++ sizeof(target_sigset_t), 0))) ++ goto efault; ++ host_to_target_sigset(p, &oldset); ++ unlock_user(p, arg3, sizeof(target_sigset_t)); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigpending: ++ { ++ sigset_t set; ++ ++ ret = get_errno(sigpending(&set)); ++ if (!is_error(ret)) { ++ if (!(p = lock_user(VERIFY_WRITE, arg1, ++ sizeof(target_sigset_t), 0))) ++ goto efault; ++ host_to_target_sigset(p, &set); ++ unlock_user(p, arg1, sizeof(target_sigset_t)); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigsuspend: ++ { ++ sigset_t set; ++ ++ if (!(p = lock_user(VERIFY_READ, arg1, ++ sizeof(target_sigset_t), 1))) ++ goto efault; ++ target_to_host_sigset(&set, p); ++ unlock_user(p, arg1, 0); ++ ret = get_errno(sigsuspend(&set)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigreturn: ++ ret = do_sigreturn(cpu_env, arg1); ++ break; ++ ++#ifdef TARGET_FREEBSD_NR_sigvec ++ case TARGET_FREEBSD_NR_sigvec: ++ ret = unimplemented(num); ++ break; ++#endif ++#ifdef TARGET_FREEBSD_NR_sigblock ++ case TARGET_FREEBSD_NR_sigblock: ++ ret = unimplemented(num); ++ break; ++#endif ++#ifdef TARGET_FREEBSD_NR_sigsetmask ++ case TARGET_FREEBSD_NR_sigsetmask: ++ ret = unimplemented(num); ++ break; ++#endif ++#ifdef TARGET_FREEBSD_NR_sigstack ++ case TARGET_FREEBSD_NR_sigstack: ++ ret = unimplemented(num); ++ break; ++#endif ++ ++ case TARGET_FREEBSD_NR_sigwait: ++ { ++ sigset_t set; ++ int sig; ++ ++ if (!(p = lock_user(VERIFY_READ, arg1, ++ sizeof(target_sigset_t), 1))) ++ goto efault; ++ target_to_host_sigset(&set, p); ++ unlock_user(p, arg1, 0); ++ ret = get_errno(sigwait(&set, &sig)); ++ if (!is_error(ret) && arg2) { ++ /* XXX */ ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigtimedwait: ++ { ++ sigset_t set; ++ struct timespec uts, *puts; ++ siginfo_t uinfo; ++ ++ if (!(p = lock_user(VERIFY_READ, arg1, ++ sizeof(target_sigset_t), 1))) ++ goto efault; ++ target_to_host_sigset(&set, p); ++ unlock_user(p, arg1, 0); ++ if (arg3) { ++ puts = &uts; ++ target_to_host_timespec(puts, arg3); ++ } else { ++ puts = NULL; ++ } ++ ret = get_errno(sigtimedwait(&set, &uinfo, puts)); ++ if (!is_error(ret) && arg2) { ++ if (!(p = lock_user(VERIFY_WRITE, arg2, ++ sizeof(target_siginfo_t), 0))) ++ goto efault; ++ host_to_target_siginfo(p, &uinfo); ++ unlock_user(p, arg2, sizeof(target_siginfo_t)); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigwaitinfo: ++ { ++ sigset_t set; ++ siginfo_t uinfo; ++ ++ if (!(p = lock_user(VERIFY_READ, arg1, ++ sizeof(target_sigset_t), 1))) ++ goto efault; ++ target_to_host_sigset(&set, p); ++ unlock_user(p, arg1, 0); ++ ret = get_errno(sigwaitinfo(&set, &uinfo)); ++ if (!is_error(ret) && arg2) { ++ if (!(p = lock_user(VERIFY_WRITE, arg2, ++ sizeof(target_siginfo_t), 0))) ++ goto efault; ++ host_to_target_siginfo(p, &uinfo); ++ unlock_user(p, arg2, sizeof(target_siginfo_t)); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigqueue: ++ { ++ union sigval value; ++ ++ value.sival_ptr = (void *)(uintptr_t)arg3; ++ ret = get_errno(sigqueue(arg1, target_to_host_signal(arg2), ++ value)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_sigaltstack: ++ { ++ ++ ret = do_sigaltstack(arg1, arg2, ++ get_sp_from_cpustate((CPUArchState *)cpu_env)); ++ } ++ ++#ifdef TARGET_FREEBSD_NR_aio_read ++ case TARGET_FREEBSD_NR_aio_read: ++#endif ++#ifdef TARGET_FREEBSD_NR_aio_write ++ case TARGET_FREEBSD_NR_aio_write: ++#endif ++#ifdef TARGET_FREEBSD_NR_aio_return ++ case TARGET_FREEBSD_NR_aio_return: ++#endif ++#ifdef TARGET_FREEBSD_NR_aio_suspend ++ case TARGET_FREEBSD_NR_aio_suspend: ++#endif ++#ifdef TARGET_FREEBSD_NR_aio_cancel ++ case TARGET_FREEBSD_NR_aio_cancel: ++#endif ++#ifdef TARGET_FREEBSD_NR_aio_error ++ case TARGET_FREEBSD_NR_aio_error: ++#endif ++#ifdef TARGET_FREEBSD_NR_aio_waitcomplete ++ case TARGET_FREEBSD_NR_aio_waitcomplete: ++#endif ++#ifdef TARGET_FREEBSD_NR_lio_listio ++ case TARGET_FREEBSD_NR_lio_listio: ++#endif ++ ++ case TARGET_FREEBSD_NR_yield: ++ case TARGET_FREEBSD_NR_sched_setparam: ++ case TARGET_FREEBSD_NR_sched_getparam: ++ case TARGET_FREEBSD_NR_sched_setscheduler: ++ case TARGET_FREEBSD_NR_sched_getscheduler: ++ case TARGET_FREEBSD_NR_sched_yield: ++ case TARGET_FREEBSD_NR_sched_get_priority_max: ++ case TARGET_FREEBSD_NR_sched_get_priority_min: ++ case TARGET_FREEBSD_NR_sched_rr_get_interval: ++ ++ ++ case TARGET_FREEBSD_NR_reboot: ++ case TARGET_FREEBSD_NR_shutdown: ++ ++ case TARGET_FREEBSD_NR_swapon: ++ case TARGET_FREEBSD_NR_swapoff: ++ ++ case TARGET_FREEBSD_NR_pdkill: ++ case TARGET_FREEBSD_NR_pdgetpid: ++ ++ case TARGET_FREEBSD_NR_thr_create: ++ case TARGET_FREEBSD_NR_thr_exit: ++ case TARGET_FREEBSD_NR_thr_self: ++ case TARGET_FREEBSD_NR_thr_suspend: ++ case TARGET_FREEBSD_NR_thr_wake: ++ case TARGET_FREEBSD_NR_thr_new: ++ case TARGET_FREEBSD_NR_thr_set_name: ++ case TARGET_FREEBSD_NR_thr_kill2: ++ ++ case TARGET_FREEBSD_NR_getcontext: ++ case TARGET_FREEBSD_NR_setcontext: ++ case TARGET_FREEBSD_NR_swapcontext: ++ ++ case TARGET_FREEBSD_NR_rtprio_thread: ++ case TARGET_FREEBSD_NR_cpuset: ++ case TARGET_FREEBSD_NR_cpuset_getid: ++ case TARGET_FREEBSD_NR_cpuset_setid: ++ case TARGET_FREEBSD_NR_cpuset_getaffinity: ++ case TARGET_FREEBSD_NR_cpuset_setaffinity: ++ ++ case TARGET_FREEBSD_NR__umtx_lock: ++ case TARGET_FREEBSD_NR__umtx_unlock: ++ ++ case TARGET_FREEBSD_NR_posix_fadvise: ++ case TARGET_FREEBSD_NR_posix_fallocate: ++ ++ case TARGET_FREEBSD_NR_rctl_get_racct: ++ case TARGET_FREEBSD_NR_rctl_get_rules: ++ case TARGET_FREEBSD_NR_rctl_add_rule: ++ 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: ++ ++#ifdef TARGET_FREEBSD_NR_getdomainname ++ case TARGET_FREEBSD_NR_getdomainname: ++#endif ++#ifdef TARGET_FREEBSD_NR_setdomainname ++ case TARGET_FREEBSD_NR_setdomainname: ++#endif ++#ifdef TARGET_FREEBSD_NR_uname ++ case TARGET_FREEBSD_NR_uname: ++#endif ++ ++ case TARGET_FREEBSD_NR_sctp_peeloff: ++ case TARGET_FREEBSD_NR_sctp_generic_sendmsg: ++ case TARGET_FREEBSD_NR_sctp_generic_recvmsg: ++ ++ 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: ++ case TARGET_FREEBSD_NR_kldunload: ++ case TARGET_FREEBSD_NR_kldunloadf: ++ case TARGET_FREEBSD_NR_kldfind: ++ case TARGET_FREEBSD_NR_kldnext: ++ case TARGET_FREEBSD_NR_kldstat: ++ case TARGET_FREEBSD_NR_kldfirstmod: ++ case TARGET_FREEBSD_NR_kldsym: ++ ++ case TARGET_FREEBSD_NR_quotactl: ++#ifdef TARGET_FREEBSD_NR_quota ++ case TARGET_FREEBSD_NR_quota: ++#endif ++ ++ case TARGET_FREEBSD_NR_adjtime: ++ ++#ifdef TARGET_FREEBSD_NR_gethostid ++ case TARGET_FREEBSD_NR_gethostid: ++#endif ++#ifdef TARGET_FREEBSD_NR_gethostname ++ case TARGET_FREEBSD_NR_gethostname: ++#endif ++#ifdef TARGET_FREEBSD_NR_sethostname ++ 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 ++#ifdef TARGET_FREEBSD_NR_getpagesize ++ case TARGET_FREEBSD_NR_getpagesize: ++#endif ++ ++ case TARGET_FREEBSD_NR_revoke: ++ ++ case TARGET_FREEBSD_NR_profil: ++ case TARGET_FREEBSD_NR_ktrace: ++ ++ case TARGET_FREEBSD_NR_jail: ++ case TARGET_FREEBSD_NR_jail_attach: ++ case TARGET_FREEBSD_NR_jail_get: ++ case TARGET_FREEBSD_NR_jail_set: ++ case TARGET_FREEBSD_NR_jail_remove: ++ ++ case TARGET_FREEBSD_NR_cap_enter: ++ case TARGET_FREEBSD_NR_cap_getmode: ++ ++ case TARGET_FREEBSD_NR_kenv: ++ case TARGET_FREEBSD_NR_uuidgen: ++ ++ case TARGET_FREEBSD_NR___mac_get_proc: ++ case TARGET_FREEBSD_NR___mac_set_proc: ++ case TARGET_FREEBSD_NR___mac_get_fd: ++ case TARGET_FREEBSD_NR___mac_set_fd: ++ case TARGET_FREEBSD_NR___mac_get_file: ++ case TARGET_FREEBSD_NR___mac_set_file: ++ case TARGET_FREEBSD_NR___mac_get_link: ++ case TARGET_FREEBSD_NR___mac_set_link: ++ case TARGET_FREEBSD_NR_mac_syscall: ++ ++ case TARGET_FREEBSD_NR_audit: ++ case TARGET_FREEBSD_NR_auditon: ++ case TARGET_FREEBSD_NR_getaudit: ++ case TARGET_FREEBSD_NR_setaudit: ++ case TARGET_FREEBSD_NR_getaudit_addr: ++ case TARGET_FREEBSD_NR_setaudit_addr: ++ case TARGET_FREEBSD_NR_auditctl: ++ ++ ++#ifdef TARGET_FREEBSD_NR_obreak ++ case TARGET_FREEBSD_NR_obreak: ++#endif ++ case TARGET_FREEBSD_NR_freebsd6_pread: ++ case TARGET_FREEBSD_NR_freebsd6_pwrite: ++ case TARGET_FREEBSD_NR_freebsd6_lseek: ++ case TARGET_FREEBSD_NR_freebsd6_truncate: ++ case TARGET_FREEBSD_NR_freebsd6_ftruncate: ++ case TARGET_FREEBSD_NR_sendfile: ++ case TARGET_FREEBSD_NR_ptrace: ++ case TARGET_FREEBSD_NR_utrace: ++ case TARGET_FREEBSD_NR_ioctl: ++ ret = unimplemented(num); ++ break; ++ ++ + default: + ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + break; +diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h +index 207ddee..ea1d25d 100644 +--- a/bsd-user/syscall_defs.h ++++ b/bsd-user/syscall_defs.h +@@ -37,8 +37,6 @@ + * @(#)signal.h 8.2 (Berkeley) 1/21/94 + */ + +-#define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ +- + #define TARGET_SIGHUP 1 /* hangup */ + #define TARGET_SIGINT 2 /* interrupt */ + #define TARGET_SIGQUIT 3 /* quit */ +@@ -71,14 +69,21 @@ + #define TARGET_SIGINFO 29 /* information request */ + #define TARGET_SIGUSR1 30 /* user defined signal 1 */ + #define TARGET_SIGUSR2 31 /* user defined signal 2 */ ++#define TARGET_SIGTHR 32 /* reserved by thread library */ ++#define TARGET_SIGLWP SIGTHR /* compatibility */ ++#define TARGET_SIGLIBRT 33 /* reserved by the real-time library */ ++#define TARGET_SIGRTMIN 65 ++#define TARGET_SIGRTMAX 126 ++#define TARGET_QEMU_ESIGRETURN 255 /* fake errno value for use by sigreturn */ ++ + + /* + * Language spec says we must list exactly one parameter, even though we + * actually supply three. Ugh! + */ +-#define TARGET_SIG_DFL (void (*)(int))0 +-#define TARGET_SIG_IGN (void (*)(int))1 +-#define TARGET_SIG_ERR (void (*)(int))-1 ++#define TARGET_SIG_DFL ((abi_long)0) /* default signal handling */ ++#define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ ++#define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ + + #define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */ + #define TARGET_SA_RESTART 0x0002 /* restart system on signal return */ +@@ -98,17 +103,503 @@ + + #define TARGET_BADSIG SIG_ERR + ++/* ++ * sigaltstack controls ++ */ + #define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ +-#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ ++#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate ++ stack */ ++ ++#define TARGET_NSIG 128 ++#define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) ++#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) ++ ++/* ++ * si_code values ++ * Digital reserves positive values for kernel-generated signals. ++ */ ++ ++/* ++ * SIGSEGV si_codes ++ */ ++#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ ++#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped ++ object */ ++/* ++ * SIGTRAP si_codes ++ */ ++#define TARGET_TRAP_BRKPT (1) /* process beakpoint */ ++#define TARGET_TRAP_TRACE (2) /* process trace trap */ + ++struct target_rlimit { ++ abi_ulong rlim_cur; ++ abi_ulong rlim_max; ++}; ++ ++#if defined(TARGET_ALPHA) ++#define TARGET_RLIM_INFINITY 0x7fffffffffffffffull ++#elif defined(TARGET_MIPS) || (defined(TARGET_SPARC) && TARGET_ABI_BITS == 32) ++#define TARGET_RLIM_INFINITY 0x7fffffffUL ++#else ++#define TARGET_RLIM_INFINITY ((abi_ulong)-1) ++#endif ++ ++#define TARGET_RLIMIT_CPU 0 ++#define TARGET_RLIMIT_FSIZE 1 ++#define TARGET_RLIMIT_DATA 2 ++#define TARGET_RLIMIT_STACK 3 ++#define TARGET_RLIMIT_CORE 4 ++#define TARGET_RLIMIT_RSS 5 ++#define TARGET_RLIMIT_MEMLOCK 6 ++#define TARGET_RLIMIT_NPROC 7 ++#define TARGET_RLIMIT_NOFILE 8 ++#define TARGET_RLIMIT_SBSIZE 9 ++#define TARGET_RLIMIT_AS 10 ++#define TARGET_RLIMIT_NPTS 11 ++#define TARGET_RLIMIT_SWAP 12 ++ ++struct target_pollfd { ++ int fd; /* file descriptor */ ++ short events; /* requested events */ ++ short revents; /* returned events */ ++}; ++ ++/* ++ * Constants used for fcntl(2). ++ */ ++ ++/* command values */ ++#define TARGET_F_DUPFD 0 ++#define TARGET_F_GETFD 1 ++#define TARGET_F_SETFD 2 ++#define TARGET_F_GETFL 3 ++#define TARGET_F_SETFL 4 ++#define TARGET_F_GETOWN 5 ++#define TARGET_F_SETOWN 6 ++#define TARGET_F_OGETLK 7 ++#define TARGET_F_OSETLK 8 ++#define TARGET_F_OSETLKW 9 ++#define TARGET_F_DUP2FD 10 ++#define TARGET_F_GETLK 11 ++#define TARGET_F_SETLK 12 ++#define TARGET_F_SETLKW 13 ++#define TARGET_F_SETLK_REMOTE 14 ++#define TARGET_F_READAHEAD 15 ++#define TARGET_F_RDAHEAD 16 ++ ++#define TARGET_O_NONBLOCK 0x00000004 ++#define TARGET_O_APPEND 0x00000008 ++#define TARGET_O_ASYNC 0x00000040 ++#define TARGET_O_DIRECT 0x00010000 ++ ++#define TARGET_SPARC_UTRAP_INSTALL 1 ++#define TARGET_SPARC_SIGTRAMP_INSTALL 2 ++ ++#include "socket.h" + #include "errno_defs.h" + + #include "freebsd/syscall_nr.h" + #include "netbsd/syscall_nr.h" + #include "openbsd/syscall_nr.h" + ++struct target_flock { ++ unsigned long long l_start; ++ unsigned long long l_len; ++ int l_pid; ++ int l_sysid; ++ short l_type; ++ short l_whence; ++} QEMU_PACKED; ++ + struct target_iovec { + abi_long iov_base; /* Starting address */ + abi_long iov_len; /* Number of bytes */ + }; + ++struct target_msghdr { ++ abi_long msg_name; /* Socket name */ ++ int msg_namelen; /* Length of name */ ++ abi_long msg_iov; /* Data blocks */ ++ abi_long msg_iovlen; /* Number of blocks */ ++ abi_long msg_control; /* Per protocol magic ++ (eg BSD file descriptor passing) */ ++ abi_long msg_controllen; /* Length of cmsg list */ ++ int msg_flags; /* flags on received message */ ++}; ++ ++struct target_cmsghdr { ++ abi_long cmsg_len; ++ int cmsg_level; ++ int cmsg_type; ++}; ++ ++#define TARGET_CMSG_DATA(cmsg) \ ++ ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1)) ++#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg) ++#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \ ++ & (size_t) ~(sizeof (abi_long) - 1)) ++#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ ++ + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr))) ++#define TARGET_CMSG_LEN(len) \ ++ (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len)) ++ ++static __inline__ struct target_cmsghdr * ++__target_cmsg_nxthdr (struct target_msghdr *__mhdr, ++ struct target_cmsghdr *__cmsg) ++{ ++ struct target_cmsghdr *__ptr; ++ ++ __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg + ++ TARGET_CMSG_ALIGN (tswapal(__cmsg->cmsg_len))); ++ if ((unsigned long)((char *)(__ptr+1) - ++ (char *)(size_t)tswapal(__mhdr->msg_control)) > ++ tswapal(__mhdr->msg_controllen)) ++ /* No more entries. */ ++ return ((struct target_cmsghdr *)0); ++ return (__cmsg); ++} ++ ++struct target_sockaddr { ++ uint16_t sa_family; ++ uint8_t sa_data[14]; ++}; ++ ++struct target_in_addr { ++ uint32_t s_addr; /* big endian */ ++}; ++ ++ ++struct target_timeval { ++ abi_long tv_sec; ++ abi_long tv_usec; ++}; ++ ++typedef abi_long target_clock_t; ++ ++struct target_rusage { ++ struct target_timeval ru_utime; /* user time used */ ++ struct target_timeval ru_stime; /* system time used */ ++ abi_long ru_maxrss; /* maximum resident set size */ ++ abi_long ru_ixrss; /* integral shared memory size */ ++ abi_long ru_idrss; /* integral unshared data size */ ++ abi_long ru_isrss; /* integral unshared stack size */ ++ abi_long ru_minflt; /* page reclaims */ ++ abi_long ru_majflt; /* page faults */ ++ abi_long ru_nswap; /* swaps */ ++ abi_long ru_inblock; /* block input operations */ ++ abi_long ru_oublock; /* block output operations */ ++ abi_long ru_msgsnd; /* messages sent */ ++ abi_long ru_msgrcv; /* messages received */ ++ abi_long ru_nsignals; /* signals received */ ++ abi_long ru_nvcsw; /* voluntary context switches */ ++ abi_long ru_nivcsw; /* involuntary context switches */ ++}; ++ ++struct target_kevent { ++ abi_ulong ident; ++ short filter; ++ u_short flags; ++ u_int fflags; ++ abi_long data; ++ abi_ulong udata; ++} __packed; ++ ++/* ++ * FreeBSD/arm uses a 64bits time_t, even in 32bits mode, so we have to ++ * add a special case here. ++ */ ++#if defined(TARGET_ARM) ++typedef uint64_t target_freebsd_time_t; ++#else ++typedef long target_freebsd_time_t; ++#endif ++ ++struct target_freebsd_timespec { ++ target_freebsd_time_t tv_sec; /* seconds */ ++ abi_long tv_nsec; /* and nanoseconds */ ++} __packed; ++ ++struct target_freebsd_timeval { ++ target_freebsd_time_t tv_sec; ++ abi_long tv_usec; ++} __packed; ++ ++struct target_freebsd_stat { ++ uint32_t st_dev; /* inode's device */ ++ uint32_t st_ino; /* inode's number */ ++ int16_t st_mode; /* inode protection mode */ ++ int16_t st_nlink; /* number of hard links */ ++ uint32_t st_uid; /* user ID of the file's owner */ ++ uint32_t st_gid; /* group ID of the file's group */ ++ uint32_t st_rdev; /* device type */ ++ struct target_freebsd_timespec st_atim; /* time of last access */ ++ struct target_freebsd_timespec st_mtim; /* time of last data modification */ ++ struct target_freebsd_timespec st_ctim; /* time of last file status change */ ++ int64_t st_size; /* file size, in bytes */ ++ int64_t st_blocks; /* blocks allocated for file */ ++ uint32_t st_blksize; /* optimal blocksize for I/O */ ++ uint32_t st_flags; /* user defined flags for file */ ++ __uint32_t st_gen; /* file generation number */ ++ __int32_t st_lspare; ++ struct target_freebsd_timespec st_birthtim; /* time of file creation */ ++ /* ++ * Explicitly pad st_birthtim to 16 bytes so that the size of ++ * struct stat is backwards compatible. We use bitfields instead ++ * of an array of chars so that this doesn't require a C99 compiler ++ * to compile if the size of the padding is 0. We use 2 bitfields ++ * to cover up to 64 bits on 32-bit machines. We assume that ++ * CHAR_BIT is 8... ++ */ ++ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec)); ++ unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec)); ++} __packed; ++ ++int __getcwd(char *, size_t); ++ ++struct target_sembuf { ++ unsigned short sem_num; /* semaphore # */ ++ short sem_op; /* semaphore operation */ ++ short sem_flg; /* operation flags */ ++}; ++ ++union target_semun { ++ int val; /* value for SETVAL */ ++ abi_ulong buf; /* buffer for IPC_STAT & IPC_SET */ ++ abi_ulong array; /* array for GETALL & SETALL */ ++}; ++ ++struct target_ipc_perm { ++ uint32_t cuid; /* creator user id */ ++ uint32_t cgid; /* creator group id */ ++ uint32_t uid; /* user id */ ++ uint32_t gid; /* group id */ ++ uint16_t mode; /* r/w permission */ ++ uint16_t seq; /* sequence # */ ++ abi_long key; /* user specified msg/sem/shm key */ ++}; ++ ++struct target_msqid_ds { ++ struct target_ipc_perm msg_perm; /* msg queue permission bits */ ++ abi_ulong msg_first; /* first message in the queue */ ++ abi_ulong msg_last; /* last message in the queue */ ++ abi_ulong msg_cbytes; /* # of bytes in use on the queue */ ++ abi_ulong msg_qnum; /* number of msgs in the queue */ ++ abi_ulong msg_qbytes; /* max # of bytes on the queue */ ++ int32_t msg_lspid; /* pid of last msgsnd() */ ++ int32_t msg_lrpid; /* pid of last msgrcv() */ ++ abi_ulong msg_stime; /* time of last msgsnd() */ ++ abi_ulong msg_rtime; /* time of last msgrcv() */ ++ abi_ulong msg_ctime; /* time of last msgctl() */ ++}; ++ ++struct target_msgbuf { ++ abi_long mtype; /* message type */ ++ char mtext[1]; /* body of message */ ++}; ++ ++struct target_semid_ds { ++ struct target_ipc_perm sem_perm; /* operation permission struct */ ++ abi_ulong sem_base; /* pointer to first semaphore in set */ ++ uint16_t sem_nsems; /* number of sems in set */ ++ abi_ulong sem_otime; /* last operation time */ ++ abi_ulong sem_ctime; /* times measured in secs */ ++}; ++ ++struct target_shmid_ds { ++ struct target_ipc_perm shm_perm; /* peration permission structure */ ++ abi_ulong shm_segsz; /* size of segment in bytes */ ++ int32_t shm_lpid; /* process ID of last shared memory op */ ++ int32_t shm_cpid; /* process ID of creator */ ++ int32_t shm_nattch; /* number of current attaches */ ++ abi_ulong shm_atime; /* time of last shmat() */ ++ abi_ulong shm_dtime; /* time of last shmdt() */ ++ abi_ulong shm_ctime; /* time of last change by shmctl() */ ++}; ++ ++/* this struct defines a stack used during syscall handling */ ++typedef struct target_sigaltstack { ++ abi_long ss_sp; ++ abi_ulong ss_size; ++ abi_long ss_flags; ++} target_stack_t; ++ ++typedef struct { ++ uint32_t __bits[TARGET_NSIG_WORDS]; ++} target_sigset_t; ++ ++struct target_sigaction { ++ abi_ulong _sa_handler; ++ int32_t sa_flags; ++ target_sigset_t sa_mask; ++}; ++ ++union target_sigval { ++ int32_t sival_int; ++ abi_ulong sival_ptr; ++ int32_t sigval_int; ++ abi_ulong sigval_ptr; ++}; ++ ++typedef struct target_siginfo { ++ int32_t si_signo; /* signal number */ ++ int32_t si_errno; /* errno association */ ++ int32_t si_code; /* signal code */ ++ int32_t si_pid; /* sending process */ ++ int32_t si_uid; /* sender's ruid */ ++ abi_ulong si_addr; /* faulting instruction */ ++ ++ union target_sigval si_value; /* signal value */ ++ ++ union { ++ struct { ++ int32_t _trapno; /* machine specific trap code */ ++ } _fault; ++ ++ /* POSIX.1b timers */ ++ struct { ++ int32_t _timerid; ++ int32_t _overrun; ++ } _timer; ++ ++ struct { ++ int32_t _mqd; ++ } _mesgp; ++ ++ /* SIGPOLL */ ++ struct { ++ int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ ++ } _poll; ++ ++ struct { ++ abi_long __spare1__; ++ int32_t __spare2_[7]; ++ } __spare__; ++ } _reason; ++} target_siginfo_t; ++ ++#if defined(TARGET_MIPS) ++ ++struct target_sigcontext { ++ target_sigset_t sc_mask; /* signal mask to retstore */ ++ int32_t sc_onstack; /* sigstack state to restore */ ++ abi_long sc_pc; /* pc at time of signal */ ++ abi_long sc_reg[32]; /* processor regs 0 to 31 */ ++ abi_long mullo, mulhi; /* mullo and mulhi registers */ ++ int32_t sc_fpused; /* fp has been used */ ++ abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ ++ abi_long sc_fpc_eir; /* fp exception instr reg */ ++ /* int32_t reserved[8]; */ ++}; ++ ++typedef struct target_mcontext { ++ int32_t mc_onstack; /* sigstack state to restore */ ++ abi_long mc_pc; /* pc at time of signal */ ++ abi_long mc_regs[32]; /* process regs 0 to 31 */ ++ abi_long sr; /* status register */ ++ abi_long mullo, mulhi; ++ int32_t mc_fpused; /* fp has been used */ ++ abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */ ++ abi_long mc_fpc_eir; /* fp exception instr reg */ ++ abi_ulong mc_tls; /* pointer to TLS area */ ++} target_mcontext_t; ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ target_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __space__[8]; ++} target_ucontext_t; ++ ++struct target_sigframe { ++ abi_ulong sf_signum; ++ abi_ulong sf_siginfo; /* code or pointer to sf_si */ ++ abi_ulong sf_ucontext; /* points to sf_uc */ ++ abi_ulong sf_addr; /* undocumented 4th arg */ ++ target_ucontext_t sf_uc; /* = *sf_uncontext */ ++ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ ++ uint32_t __spare__[2]; ++}; ++ ++#elif defined(TARGET_SPARC64) ++ ++struct target_mcontext { ++ uint64_t mc_global[8]; ++ uint64_t mc_out[8]; ++ uint64_t mc_local[8]; ++ uint64_t mc_in[8]; ++ uint32_t mc_fp[64]; ++} __aligned(64); ++ ++typedef struct target_mcontext target_mcontext_t; ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ target_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __space__[8]; ++} target_ucontext_t; ++ ++struct target_sigframe { ++ target_ucontext_t sf_uc; ++ target_siginfo_t sf_si; ++}; ++ ++#else ++ ++typedef target_ulong target_mcontext_t; /* dummy */ ++ ++#endif ++ ++/* XXX where did this come from? ++typedef struct target_ucontext { ++ target_ulong uc_flags; ++ target_ulong uc_link; ++ target_stack_t uc_stack; ++ target_mcontext_t uc_mcontext; ++ target_ulong uc_filer[80]; ++ target_sigset_t uc_sigmask; ++} target_ucontext_t; ++*/ ++ ++ ++#ifdef BSWAP_NEEDED ++static inline void ++tswap_sigset(target_sigset_t *d, const target_sigset_t *s) ++{ ++ int i; ++ ++ for(i = 0;i < TARGET_NSIG_WORDS; i++) ++ d->__bits[i] = tswapal(s->__bits[i]); ++} ++ ++#else ++static inline void ++tswap_sigset(target_sigset_t *d, const target_sigset_t *s) ++{ ++ ++ *d = *s; ++} ++#endif ++ ++/* XXX ++static inline void ++target_siginitset(target_sigset_t *d, abi_ulong set) ++{ ++ int i; ++ ++ d->sig[0] = set; ++ for(i = 1;i < TARGET_NSIG_WORDS; i++) ++ d->sig[i] = 0; ++} ++*/ ++ ++void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); ++void target_to_host_sigset(sigset_t *d, const target_sigset_t *s); ++void host_to_target_old_sigset(abi_ulong *old_sigset, const sigset_t *sigset); ++void target_to_host_old_sigset(sigset_t *sigset, const abi_ulong *old_sigset); ++int do_sigaction(int sig, const struct target_sigaction *act, ++ struct target_sigaction *oact); +diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h +index 659cd40..ea89f5a 100644 +--- a/bsd-user/x86_64/target_signal.h ++++ b/bsd-user/x86_64/target_signal.h +@@ -3,17 +3,16 @@ + + #include "cpu.h" + +-/* this struct defines a stack used during syscall handling */ +- +-typedef struct target_sigaltstack { +- abi_ulong ss_sp; +- abi_long ss_flags; +- abi_ulong ss_size; +-} target_stack_t; +- + static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) + { + return state->regs[R_ESP]; + } + ++#define TARGET_SS_ONSTACK 0x0001 /* take signal on alternate stack */ ++#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on ++ alternate stack */ ++ ++#define TARGET_MINSIGSTKSZ (512 * 4) ++#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/x86_64/target_vmparam.h b/bsd-user/x86_64/target_vmparam.h +new file mode 100644 +index 0000000..aa5e0e0 +--- /dev/null ++++ b/bsd-user/x86_64/target_vmparam.h +@@ -0,0 +1,28 @@ ++#ifndef _TARGET_VMPARAM_H_ ++#define _TARGET_VMPARAM_H_ ++ ++#if defined(__FreeBSD__) ++#define TARGET_VM_MAXUSER_ADDRESS (0x0000800000000000UL) ++ ++#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE) ++ ++struct target_ps_strings { ++ abi_ulong ps_argvstr; ++ uint32_t ps_nargvstr; ++ abi_ulong ps_envstr; ++ uint32_t ps_nenvstr; ++}; ++ ++#define TARGET_SPACE_USRSPACE 4096 ++#define TARGET_ARG_MAX 262144 ++ ++#define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) ++ ++#define TARGET_SZSIGCODE 0 ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++#endif ++ ++#endif /* _TARGET_VMPARAM_H_ */ +diff --git a/configure b/configure +index 169b9bd..34eca43 100755 +--- a/configure ++++ b/configure +@@ -1018,6 +1018,10 @@ x86_64-bsd-user \ + sparc-bsd-user \ + sparc64-bsd-user \ + arm-bsd-user \ ++armeb-bsd-user \ ++mips-bsd-user \ ++mipsel-bsd-user \ ++mips64-bsd-user \ + " + fi + +diff --git a/default-configs/armeb-bsd-user.mak b/default-configs/armeb-bsd-user.mak +new file mode 100644 +index 0000000..1b6fe65 +--- /dev/null ++++ b/default-configs/armeb-bsd-user.mak +@@ -0,0 +1,3 @@ ++# Default configuration for armeb-bsd-user ++ ++CONFIG_GDBSTUB_XML=y +diff --git a/default-configs/mips-bsd-user.mak b/default-configs/mips-bsd-user.mak +new file mode 100644 +index 0000000..3fb129a +--- /dev/null ++++ b/default-configs/mips-bsd-user.mak +@@ -0,0 +1 @@ ++# Default configuration for mips-bsd-user +diff --git a/default-configs/mips64-bsd-user.mak b/default-configs/mips64-bsd-user.mak +new file mode 100644 +index 0000000..d4e72a6 +--- /dev/null ++++ b/default-configs/mips64-bsd-user.mak +@@ -0,0 +1 @@ ++# Default configuration for mips64-bsd-user +diff --git a/default-configs/mipsel-bsd-user.mak b/default-configs/mipsel-bsd-user.mak +new file mode 100644 +index 0000000..312b9d5 +--- /dev/null ++++ b/default-configs/mipsel-bsd-user.mak +@@ -0,0 +1 @@ ++# Default configuration for mipsel-bsd-user +diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h +index bf094a3..030937c 100644 +--- a/target-mips/mips-defs.h ++++ b/target-mips/mips-defs.h +@@ -10,8 +10,14 @@ + + #if defined(TARGET_MIPS64) + #define TARGET_LONG_BITS 64 +-#define TARGET_PHYS_ADDR_SPACE_BITS 36 +-#define TARGET_VIRT_ADDR_SPACE_BITS 42 ++//#define TARGET_PHYS_ADDR_SPACE_BITS 36 ++#define TARGET_PHYS_ADDR_SPACE_BITS 59 ++# ifdef TARGET_ABI32 ++# define TARGET_VIRT_ADDR_SPACE_BITS 32 ++# else ++//# define TARGET_VIRT_ADDR_SPACE_BITS 42 ++# define TARGET_VIRT_ADDR_SPACE_BITS 62 ++# endif + #else + #define TARGET_LONG_BITS 32 + #define TARGET_PHYS_ADDR_SPACE_BITS 36 +diff --git a/user-exec.c b/user-exec.c +index b9ea9dd..9ad4858 100644 +--- a/user-exec.c ++++ b/user-exec.c +@@ -34,11 +34,11 @@ + #undef EDI + #undef EIP + #include +-#ifdef __linux__ ++#if defined(__linux__) || defined(__FreeBSD__) + #include + #endif + +-//#define DEBUG_SIGNAL ++#define DEBUG_SIGNAL + + static void exception_action(CPUArchState *env1) + { +@@ -58,6 +58,8 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc) + struct ucontext *uc = puc; + #elif defined(__OpenBSD__) + struct sigcontext *uc = puc; ++#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) ++ ucontext_t *uc = puc; + #endif + + #ifndef CONFIG_TCG_PASS_AREG0 +@@ -76,6 +78,8 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc) + #endif + #elif defined(__OpenBSD__) + sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); ++#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) ++ sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); + #endif + } + env1->exception_index = -1; Index: files/patch-z2b-bsd-user-sson-002b @@ -0,0 +1,217 @@ +diff --git a/bsd-user/signal.c b/bsd-user/signal.c +index 0502a6a..52441c4 100644 +--- a/bsd-user/signal.c ++++ b/bsd-user/signal.c +@@ -31,7 +31,7 @@ + #include "qemu.h" + #include "target_signal.h" + +-// #define DEBUG_SIGNAL ++//#define DEBUG_SIGNAL + + #ifndef _NSIG + #define _NSIG 128 +@@ -441,7 +441,7 @@ host_signal_handler(int host_signum, siginfo_t *info, void *puc) + * we forward to it some signals. + */ + if ((host_signum == SIGSEGV || host_signum == SIGBUS) && +- info->si_code > 0) { ++ info->si_code < 0x10000) { + if (cpu_signal_handler(host_signum, info, puc)) + return; + } +@@ -1099,6 +1099,7 @@ signal_init(void) + + sigfillset(&act.sa_mask); + act.sa_sigaction = host_signal_handler; ++ act.sa_flags = SA_SIGINFO; + + for (i = 1; i <= TARGET_NSIG; i++) { + host_sig = target_to_host_signal(i); +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index c627c62..625c3cf 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -3544,6 +3544,30 @@ do_stat: + } + break; + ++#ifdef TARGET_FREEBSD_NR_pdwait4 ++ case TARGET_FREEBSD_NR_pdwait4: ++ { ++ int status; ++ abi_long status_ptr = arg2; ++ struct rusage rusage, *rusage_ptr; ++ abi_long target_rusage = arg4; ++ ++ if (target_rusage) ++ rusage_ptr = &rusage; ++ else ++ rusage_ptr = NULL; ++ ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); ++ if (!is_error(ret)) { ++ status = host_to_target_waitstatus(status); ++ if (put_user_s32(status, status_ptr)) ++ goto efault; ++ if (target_rusage) ++ host_to_target_rusage(target_rusage, &rusage); ++ } ++ } ++ break; ++#endif /* TARGET_FREEBSD_NR_pdwait4 */ ++ + case TARGET_FREEBSD_NR_accept: + ret = do_accept(arg1, arg2, arg3); + break; +@@ -3803,6 +3827,20 @@ do_stat: + break; + #endif + ++ case TARGET_FREEBSD_NR_pdkill: ++ ret = get_errno(pdkill(arg1, target_to_host_signal(arg2))); ++ break; ++ ++ case TARGET_FREEBSD_NR_pdgetpid: ++ { ++ pid_t pid; ++ ++ ret = get_errno(pdgetpid(arg1, &pid)); ++ if (put_user_u32(pid, arg2)) ++ goto efault; ++ } ++ break; ++ + case TARGET_FREEBSD_NR_sigaction: + { + struct target_sigaction *old_act, act, oact, *pact; +@@ -4014,27 +4052,88 @@ do_stat: + + #ifdef TARGET_FREEBSD_NR_aio_read + case TARGET_FREEBSD_NR_aio_read: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_aio_write + case TARGET_FREEBSD_NR_aio_write: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_aio_return + case TARGET_FREEBSD_NR_aio_return: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_aio_suspend + case TARGET_FREEBSD_NR_aio_suspend: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_aio_cancel + case TARGET_FREEBSD_NR_aio_cancel: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_aio_error + case TARGET_FREEBSD_NR_aio_error: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_aio_waitcomplete + case TARGET_FREEBSD_NR_aio_waitcomplete: ++ ret = unimplemented(num); ++ break; + #endif + #ifdef TARGET_FREEBSD_NR_lio_listio + case TARGET_FREEBSD_NR_lio_listio: ++ ret = unimplemented(num); ++ break; ++#endif ++ ++#if 0 /* XXX not supported in libc yet, it seems (10.0 addition). */ ++ case TARGET_FREEBSD_NR_posix_fadvise: ++ { ++ off_t offset = arg2, len = arg3; ++ int advice = arg4; ++ ++#if TARGET_ABI_BITS == 32 ++ if (regpairs_aligned(cpu_env)) { ++ offset = target_offset64(arg3, arg4); ++ len = target_offset64(arg5, arg6); ++ advice = arg7; ++ } else { ++ offset = target_offset64(arg2, arg3); ++ len = target_offset64(arg4, arg5); ++ advice = arg6; ++ } ++#endif ++ ret = get_errno(posix_fadvise(arg1, offset, len, advice)); ++ } ++ break; ++#endif ++ ++ case TARGET_FREEBSD_NR_posix_fallocate: ++ { ++ off_t offset = arg2, len = arg3; ++ ++#if TARGET_ABI_BITS == 32 ++ if (regpairs_aligned(cpu_env)) { ++ offset = target_offset64(arg3, arg4); ++ len = target_offset64(arg5, arg6); ++ } else { ++ offset = target_offset64(arg2, arg3); ++ len = target_offset64(arg4, arg5); ++ } ++#endif ++ ret = get_errno(posix_fallocate(arg1, offset, len)); ++ } ++ break; ++ ++#ifdef TARGET_FREEBSD_posix_openpt ++ case TARGET_FREEBSD_posix_openpt: ++ ret = get_errno(posix_openpt(arg1)); ++ break; + #endif + + case TARGET_FREEBSD_NR_yield: +@@ -4054,9 +4153,6 @@ do_stat: + case TARGET_FREEBSD_NR_swapon: + case TARGET_FREEBSD_NR_swapoff: + +- case TARGET_FREEBSD_NR_pdkill: +- case TARGET_FREEBSD_NR_pdgetpid: +- + case TARGET_FREEBSD_NR_thr_create: + case TARGET_FREEBSD_NR_thr_exit: + case TARGET_FREEBSD_NR_thr_self: +@@ -4080,9 +4176,6 @@ do_stat: + case TARGET_FREEBSD_NR__umtx_lock: + case TARGET_FREEBSD_NR__umtx_unlock: + +- case TARGET_FREEBSD_NR_posix_fadvise: +- case TARGET_FREEBSD_NR_posix_fallocate: +- + case TARGET_FREEBSD_NR_rctl_get_racct: + case TARGET_FREEBSD_NR_rctl_get_rules: + case TARGET_FREEBSD_NR_rctl_add_rule: +diff --git a/user-exec.c b/user-exec.c +index 9ad4858..bf29e84 100644 +--- a/user-exec.c ++++ b/user-exec.c +@@ -38,7 +38,7 @@ + #include + #endif + +-#define DEBUG_SIGNAL ++//#define DEBUG_SIGNAL + + static void exception_action(CPUArchState *env1) + { +@@ -103,7 +103,7 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, + } + #endif + #if defined(DEBUG_SIGNAL) +- qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", ++ qemu_printf("qemu: SIGSEGV pc=0x%08lx address=0x%08lx w=%d oldset=0x%08lx\n", + pc, address, is_write, *(unsigned long *)old_set); + #endif + /* XXX: locking issue */ Index: files/patch-z2c-bsd-user-sson-002c @@ -0,0 +1,2301 @@ +diff --git a/bsd-user/arm/target_signal.h b/bsd-user/arm/target_signal.h +index 19cc188..6b7bb67 100644 +--- a/bsd-user/arm/target_signal.h ++++ b/bsd-user/arm/target_signal.h +@@ -11,4 +11,29 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) + #define TARGET_MINSIGSTKSZ (1024 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + ++typedef target_ulong target_mcontext_t; /* dummy */ ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ ++static inline int ++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "ARM doesn't have support for get_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ ++static inline int ++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "ARM doesn't have support for set_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list +index 1edf412..b09f766 100644 +--- a/bsd-user/freebsd/strace.list ++++ b/bsd-user/freebsd/strace.list +@@ -38,6 +38,7 @@ + { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_getcontext, "getcontext", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL }, +@@ -123,6 +124,7 @@ + { TARGET_FREEBSD_NR_semop, "semop", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_sendmsg, "sendmsg", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_sendto, "sendto", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_setcontext, "setcontext", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_setegid, "setegid", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_seteuid, "seteuid", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_setgid, "setgid", NULL, NULL, NULL }, +@@ -160,6 +162,15 @@ + { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_kill, "thr_kill", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_kill2, "thr_kill2", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_new, "thr_new", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_self, "thr_self", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_set_name, "thr_set_name", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_suspend, "thr_suspend", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_thr_wake, "thr_wake", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_truncate, "truncate", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_umask, "umask", "%s(%#o)", NULL, NULL }, + { TARGET_FREEBSD_NR_unlink, "unlink", "%s(\"%s\")", NULL, NULL }, +diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h +index 285e7f9..28481ce 100644 +--- a/bsd-user/i386/target_signal.h ++++ b/bsd-user/i386/target_signal.h +@@ -11,4 +11,29 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) + #define TARGET_MINSIGSTKSZ (512 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + ++typedef target_ulong target_mcontext_t; /* dummy */ ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ ++static inline int ++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "i386 doesn't have support for get_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ ++static inline int ++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "i386 doesn't have support for set_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/main.c b/bsd-user/main.c +index 146f022..7a99537 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -34,6 +34,10 @@ + #include "qemu-timer.h" + #include "envlist.h" + ++#if defined(CONFIG_USE_NPTL) && defined(__FreeBSD__) ++#include ++#endif ++ + #define DEBUG_LOGFILE "/tmp/qemu.log" + + int singlestep; +@@ -70,42 +74,186 @@ int cpu_get_pic_interrupt(CPUX86State *env) + } + #endif + +-/* These are no-ops because we are not threadsafe. */ +-static inline void cpu_exec_start(CPUArchState *env) ++#if defined(CONFIG_USE_NPTL) ++/* Helper routines for implementing atomic operations. */ ++ ++/* ++ * To implement exclusive operations we force all cpus to synchronize. ++ * We don't require a full sync, only that no cpus are executing guest code. ++ * The alternative is to map target atomic ops onto host eqivalents, ++ * which requires quite a lot of per host/target work. ++ */ ++static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER; ++static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER; ++static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER; ++static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER; ++static int pending_cpus; ++ ++/* Make sure everything is in a consistent state for calling fork(). */ ++void fork_start(void) + { ++ pthread_mutex_lock(&tb_lock); ++ pthread_mutex_lock(&exclusive_lock); ++ mmap_fork_start(); + } + +-static inline void cpu_exec_end(CPUArchState *env) ++void fork_end(int child) + { ++ mmap_fork_end(child); ++ if (child) { ++ /* ++ * Child processes created by fork() only have a single thread. ++ * Discard information about the parent threads. ++ */ ++ first_cpu = thread_env; ++ thread_env->next_cpu = NULL; ++ pending_cpus = 0; ++ pthread_mutex_init(&exclusive_lock, NULL); ++ pthread_mutex_init(&cpu_list_mutex, NULL); ++ pthread_cond_init(&exclusive_cond, NULL); ++ pthread_cond_init(&exclusive_resume, NULL); ++ pthread_mutex_init(&tb_lock, NULL); ++ gdbserver_fork(thread_env); ++ } else { ++ pthread_mutex_unlock(&exclusive_lock); ++ pthread_mutex_unlock(&tb_lock); ++ } + } + +-static inline void start_exclusive(void) ++/* ++ * Wait for pending exclusive operations to complete. The exclusive lock ++ * must be held. ++ */ ++static inline void ++exclusive_idle(void) + { ++ while (pending_cpus) { ++ pthread_cond_wait(&exclusive_resume, &exclusive_lock); ++ } + } + +-static inline void end_exclusive(void) ++/* Start an exclusive operation. Must only be called outside of cpu_exec. */ ++static inline void ++start_exclusive(void) + { ++ CPUArchState *other; ++ ++ pthread_mutex_lock(&exclusive_lock); ++ exclusive_idle(); ++ ++ pending_cpus = 1; ++ /* Make all other cpus stop executing. */ ++ for (other = first_cpu; other; other = other->next_cpu) { ++ if (other->running) { ++ pending_cpus++; ++ cpu_exit(other); ++ } ++ } ++ if (pending_cpus > 1) { ++ pthread_cond_wait(&exclusive_cond, &exclusive_lock); ++ } + } + +-void fork_start(void) ++/* Finish an exclusive operation. */ ++static inline void ++end_exclusive(void) + { ++ pending_cpus = 0; ++ pthread_cond_broadcast(&exclusive_resume); ++ pthread_mutex_unlock(&exclusive_lock); + } + +-void fork_end(int child) ++/* Wait for exclusive ops to finish, and begin cpu execution. */ ++static inline void ++cpu_exec_start(CPUArchState *env) ++{ ++ pthread_mutex_lock(&exclusive_lock); ++ exclusive_idle(); ++ env->running = 1; ++ pthread_mutex_unlock(&exclusive_lock); ++} ++ ++/* Mark cpu as not excuting, and release pending exclusive ops. */ ++static inline void ++cpu_exec_end(CPUArchState *env) ++{ ++ pthread_mutex_lock(&exclusive_lock); ++ env->running = 0; ++ if (pending_cpus > 1) { ++ pending_cpus--; ++ if (pending_cpus == 1) { ++ pthread_cond_signal(&exclusive_cond); ++ } ++ } ++ exclusive_idle(); ++ pthread_mutex_unlock(&exclusive_lock); ++} ++ ++void ++cpu_list_lock(void) ++{ ++ pthread_mutex_lock(&cpu_list_mutex); ++} ++ ++void ++cpu_list_unlock(void) ++{ ++ pthread_mutex_unlock(&cpu_list_mutex); ++} ++ ++#else /* ! CONFIG_USE_NPTL */ ++ ++/* These are no-ops because we are not threadsafe. */ ++void ++fork_start(void) ++{ ++} ++ ++void ++fork_end(int child) + { + if (child) { + gdbserver_fork(thread_env); + } + } + +-void cpu_list_lock(void) ++static inline void ++exclusive_idle(void) ++{ ++} ++ ++static inline void ++start_exclusive(void) + { + } + +-void cpu_list_unlock(void) ++static inline void ++end_exclusive(void) + { + } + ++static inline void ++cpu_exec_start(CPUArchState *env) ++{ ++} ++ ++ ++static inline void ++cpu_exec_end(CPUArchState *env) ++{ ++} ++ ++void ++cpu_list_lock(void) ++{ ++} ++ ++void ++cpu_list_unlock(void) ++{ ++} ++#endif /* CONFIG_USE_NPTL */ ++ + #ifdef TARGET_I386 + /***********************************************************/ + /* CPUX86 core interface */ +@@ -740,7 +888,10 @@ void cpu_loop(CPUMIPSState *env) + + for(;;) { + cpu_exec_start(env); ++ /* XXX there is a concurrency problem - giant lock for now */ ++ pthread_mutex_lock(&exclusive_lock); /* XXX */ + trapnr = cpu_mips_exec(env); ++ pthread_mutex_unlock(&exclusive_lock); /* XXX */ + cpu_exec_end(env); + switch(trapnr) { + case EXCP_SYSCALL: /* syscall exception */ +@@ -1206,6 +1357,18 @@ static void usage(void) + + THREAD CPUArchState *thread_env; + ++void task_settid(TaskState *ts) ++{ ++ if (0 == ts->ts_tid) { ++#ifdef CONFIG_USE_NPTL ++ (void)thr_self(&ts->ts_tid); ++#else ++ /* When no threads then just use PID */ ++ ts->ts_tid = getpid(); ++#endif ++ } ++} ++ + void stop_all_tasks(void) + { + /* +diff --git a/bsd-user/mips/target_signal.h b/bsd-user/mips/target_signal.h +index 28871c3..484cfd8 100644 +--- a/bsd-user/mips/target_signal.h ++++ b/bsd-user/mips/target_signal.h +@@ -6,9 +6,187 @@ + #define TARGET_MINSIGSTKSZ (512 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + +-static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) ++struct target_sigcontext { ++ target_sigset_t sc_mask; /* signal mask to retstore */ ++ int32_t sc_onstack; /* sigstack state to restore */ ++ abi_long sc_pc; /* pc at time of signal */ ++ abi_long sc_reg[32]; /* processor regs 0 to 31 */ ++ abi_long mullo, mulhi; /* mullo and mulhi registers */ ++ int32_t sc_fpused; /* fp has been used */ ++ abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ ++ abi_long sc_fpc_eir; /* fp exception instr reg */ ++ /* int32_t reserved[8]; */ ++}; ++ ++typedef struct target_mcontext { ++ int32_t mc_onstack; /* sigstack state to restore */ ++ abi_long mc_pc; /* pc at time of signal */ ++ abi_long mc_regs[32]; /* process regs 0 to 31 */ ++ abi_long sr; /* status register */ ++ abi_long mullo, mulhi; ++ int32_t mc_fpused; /* fp has been used */ ++ abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */ ++ abi_long mc_fpc_eir; /* fp exception instr reg */ ++ abi_ulong mc_tls; /* pointer to TLS area */ ++} target_mcontext_t; ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ ++struct target_sigframe { ++ abi_ulong sf_signum; ++ abi_ulong sf_siginfo; /* code or pointer to sf_si */ ++ abi_ulong sf_ucontext; /* points to sf_uc */ ++ abi_ulong sf_addr; /* undocumented 4th arg */ ++ target_ucontext_t sf_uc; /* = *sf_uncontext */ ++ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ ++ uint32_t __spare__[2]; ++}; ++ ++ ++/* Get the stack pointer. */ ++static inline abi_ulong ++get_sp_from_cpustate(CPUMIPSState *state) + { + return state->active_tc.gpr[29]; + } + ++/* ++ * Compare to mips/mips/pm_machdep.c sendsig() ++ * Assumes that "frame" memory is locked. ++ */ ++static inline int ++set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, ++ abi_ulong frame_addr, struct target_sigaction *ka) ++{ ++ ++ frame->sf_signum = sig; ++ frame->sf_siginfo = 0; ++ frame->sf_ucontext = 0; ++ ++ frame->sf_si.si_signo = sig; ++ frame->sf_si.si_code = TARGET_SA_SIGINFO; ++ frame->sf_si.si_addr = regs->CP0_BadVAddr; ++ ++ /* ++ * Arguments to signal handler: ++ * a0 ($4) = signal number ++ * a1 ($5) = siginfo pointer ++ * a2 ($6) = ucontext pointer ++ * PC = signal handler pointer ++ * t9 ($25) = signal handler pointer ++ * $29 = point to sigframe struct ++ * ra ($31) = sigtramp at base of user stack ++ */ ++ regs->active_tc.gpr[ 4] = sig; ++ regs->active_tc.gpr[ 5] = frame_addr + ++ offsetof(struct target_sigframe, sf_si); ++ regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; ++ regs->active_tc.gpr[29] = frame_addr; ++ regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; ++ ++ return (0); ++} ++ ++/* ++ * Compare to mips/mips/pm_machdep.c get_mcontext() ++ * Assumes that the memory is locked if mcp points to user memory. ++ */ ++static inline int ++get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags) ++{ ++ int i, err = 0; ++ ++ if (flags & TARGET_MC_ADD_MAGIC) { ++ mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC); ++ } else { ++ mcp->mc_regs[0] = 0; ++ } ++ ++ if (flags & TARGET_MC_SET_ONSTACK) { ++ mcp->mc_onstack = tswapal(1); ++ } else { ++ mcp->mc_onstack = 0; ++ } ++ ++ for(i = 1; i < 32; i++) ++ mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]); ++ ++#if 0 /* XXX FP is not used right now. */ ++ abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0; ++ ++ mcp->mc_fpused = used_fp; ++ if (used_fp) { ++ preempt_disable(); ++ if (!is_fpu_owner()) { ++ own_fpu(); ++ for(i = 0; i < 33; i++) ++ mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]); ++ } ++ preempt_enable(); ++ } ++#else ++ mcp->mc_fpused = 0; ++#endif ++ ++ if (flags & TARGET_MC_GET_CLEAR_RET) { ++ mcp->mc_regs[2] = 0; /* v0 = 0 */ ++ mcp->mc_regs[3] = 0; /* v1 = 0 */ ++ mcp->mc_regs[7] = 0; /* a3 = 0 */ ++ } ++ ++ mcp->mc_pc = tswapal(regs->active_tc.PC); ++ mcp->mullo = tswapal(regs->active_tc.LO[0]); ++ mcp->mulhi = tswapal(regs->active_tc.HI[0]); ++ mcp->mc_tls = tswapal(regs->tls_value); ++ ++ /* Don't do any of the status and cause registers. */ ++ ++ return (err); ++} ++ ++/* Compare to mips/mips/pm_machdep.c set_mcontext() */ ++static inline int ++set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags) ++{ ++ int i, err = 0; ++ ++ for(i = 1; i < 32; i++) ++ regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]); ++ ++#if 0 /* XXX FP is not used right now */ ++ abi_ulong used_fp = 0; ++ ++ used_fp = tswapal(mcp->mc_fpused) ++ conditional_used_math(used_fp); ++ ++ preempt_disabled(); ++ if (used_math()) { ++ /* restore fpu context if we have used it before */ ++ own_fpu(); ++ for (i = 0; i < 32; i++) ++ regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]); ++ } else { ++ /* Signal handler may have used FPU. Give it up. */ ++ lose_fpu(); ++ } ++ preempt_enable(); ++#endif ++ ++ regs->CP0_EPC = tswapal(mcp->mc_pc); ++ regs->active_tc.LO[0] = tswapal(mcp->mullo); ++ regs->active_tc.HI[0] = tswapal(mcp->mulhi); ++ regs->tls_value = tswapal(mcp->mc_tls); ++ ++ /* Don't do any of the status and cause registers. */ ++ ++ return (err); ++} ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/mips64/target_signal.h b/bsd-user/mips64/target_signal.h +index d671f4e..e9c8a9f 100644 +--- a/bsd-user/mips64/target_signal.h ++++ b/bsd-user/mips64/target_signal.h +@@ -7,11 +7,186 @@ + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + #define TARGET_SZSIGCODE 16 + +-#define TARGET_UCONTEXT_MAGIC 0xACEDBADE ++struct target_sigcontext { ++ target_sigset_t sc_mask; /* signal mask to retstore */ ++ int32_t sc_onstack; /* sigstack state to restore */ ++ abi_long sc_pc; /* pc at time of signal */ ++ abi_long sc_reg[32]; /* processor regs 0 to 31 */ ++ abi_long mullo, mulhi; /* mullo and mulhi registers */ ++ int32_t sc_fpused; /* fp has been used */ ++ abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ ++ abi_long sc_fpc_eir; /* fp exception instr reg */ ++ /* int32_t reserved[8]; */ ++}; + +-static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) ++typedef struct target_mcontext { ++ int32_t mc_onstack; /* sigstack state to restore */ ++ abi_long mc_pc; /* pc at time of signal */ ++ abi_long mc_regs[32]; /* process regs 0 to 31 */ ++ abi_long sr; /* status register */ ++ abi_long mullo, mulhi; ++ int32_t mc_fpused; /* fp has been used */ ++ abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */ ++ abi_long mc_fpc_eir; /* fp exception instr reg */ ++ abi_ulong mc_tls; /* pointer to TLS area */ ++} target_mcontext_t; ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ ++struct target_sigframe { ++ abi_ulong sf_signum; ++ abi_ulong sf_siginfo; /* code or pointer to sf_si */ ++ abi_ulong sf_ucontext; /* points to sf_uc */ ++ abi_ulong sf_addr; /* undocumented 4th arg */ ++ target_ucontext_t sf_uc; /* = *sf_uncontext */ ++ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ ++ uint32_t __spare__[2]; ++}; ++ ++static inline abi_ulong ++get_sp_from_cpustate(CPUMIPSState *state) + { + return state->active_tc.gpr[29]; + } + ++/* ++ * Compare to mips/mips/pm_machdep.c sendsig() ++ * Assumes that "frame" memory is locked. ++ */ ++static inline int ++set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, ++ abi_ulong frame_addr, struct target_sigaction *ka) ++{ ++ ++ frame->sf_signum = sig; ++ frame->sf_siginfo = 0; ++ frame->sf_ucontext = 0; ++ ++ frame->sf_si.si_signo = sig; ++ frame->sf_si.si_code = TARGET_SA_SIGINFO; ++ frame->sf_si.si_addr = regs->CP0_BadVAddr; ++ ++ /* ++ * Arguments to signal handler: ++ * a0 ($4) = signal number ++ * a1 ($5) = siginfo pointer ++ * a2 ($6) = ucontext pointer ++ * PC = signal handler pointer ++ * t9 ($25) = signal handler pointer ++ * $29 = point to sigframe struct ++ * ra ($31) = sigtramp at base of user stack ++ */ ++ regs->active_tc.gpr[ 4] = sig; ++ regs->active_tc.gpr[ 5] = frame_addr + ++ offsetof(struct target_sigframe, sf_si); ++ regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; ++ regs->active_tc.gpr[29] = frame_addr; ++ regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; ++ ++ return (0); ++} ++ ++/* ++ * Compare to mips/mips/pm_machdep.c get_mcontext() ++ * Assumes that the memory is locked if mcp points to user memory. ++ */ ++static inline int ++get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags) ++{ ++ int i, err = 0; ++ ++ if (flags & TARGET_MC_ADD_MAGIC) { ++ mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC); ++ } else { ++ mcp->mc_regs[0] = 0; ++ } ++ ++ if (flags & TARGET_MC_SET_ONSTACK) { ++ mcp->mc_onstack = tswapal(1); ++ } else { ++ mcp->mc_onstack = 0; ++ } ++ ++ for(i = 1; i < 32; i++) ++ mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]); ++ ++#if 0 /* XXX FP is not used right now */ ++ abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0; ++ ++ mcp->mc_fpused = used_fp; ++ if (used_fp) { ++ preempt_disable(); ++ if (!is_fpu_owner()) { ++ own_fpu(); ++ for(i = 0; i < 33; i++) ++ mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]); ++ } ++ preempt_enable(); ++ } ++#else ++ mcp->mc_fpused = 0; ++#endif ++ ++ if (flags & TARGET_MC_GET_CLEAR_RET) { ++ mcp->mc_regs[2] = 0; /* v0 = 0 */ ++ mcp->mc_regs[3] = 0; /* v1 = 0 */ ++ mcp->mc_regs[7] = 0; /* a3 = 0 */ ++ } ++ ++ mcp->mc_pc = tswapal(regs->active_tc.PC); ++ mcp->mullo = tswapal(regs->active_tc.LO[0]); ++ mcp->mulhi = tswapal(regs->active_tc.HI[0]); ++ mcp->mc_tls = tswapal(regs->tls_value); ++ ++ /* Don't do any of the status and cause registers. */ ++ ++ return (err); ++} ++ ++/* Compare to mips/mips/pm_machdep.c set_mcontext() */ ++static inline int ++set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, int flags) ++{ ++ int i, err = 0; ++ ++ for(i = 1; i < 32; i++) ++ regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]); ++ ++#if 0 /* XXX FP is not used right now */ ++ abi_ulong used_fp = 0; ++ ++ used_fp = tswapal(mcp->mc_fpused) ++ conditional_used_math(used_fp); ++ ++ preempt_disabled(); ++ if (used_math()) { ++ /* restore fpu context if we have used it before */ ++ own_fpu(); ++ for (i = 0; i < 32; i++) ++ regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]); ++ } else { ++ /* Signal handler may have used FPU. Give it up. */ ++ lose_fpu(); ++ } ++ preempt_enable(); ++#endif ++ ++ regs->CP0_EPC = tswapal(mcp->mc_pc); ++ regs->active_tc.LO[0] = tswapal(mcp->mullo); ++ regs->active_tc.HI[0] = tswapal(mcp->mulhi); ++ regs->tls_value = tswapal(mcp->mc_tls); ++ ++ /* Don't do any of the status and cause registers. */ ++ ++ return (err); ++} ++ + #endif /* TARGET_SIGNAL_H */ ++ +diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c +--- a/bsd-user/mmap.c ++++ b/bsd-user/mmap.c +@@ -74,6 +74,8 @@ void mmap_unlock(void) + } + #endif + ++#if 0 /* XXX not sure why we need our own g_malloc() and friends. ++ g_strdup(), however, has serious problems with this g_malloc/g_free */ + static void *bsd_vmalloc(size_t size) + { + void *p; +@@ -133,6 +135,7 @@ void *g_realloc(void *ptr, size_t size) + g_free(ptr); + return new_ptr; + } ++#endif + + /* NOTE: all the constants are the HOST ones, but addresses are target. */ + int target_mprotect(abi_ulong start, abi_ulong len, int prot) +diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h +index ab7e18c..9d4edbf 100644 +--- a/bsd-user/qemu.h ++++ b/bsd-user/qemu.h +@@ -80,7 +80,7 @@ struct emulated_sigtable { + typedef struct TaskState { + struct TaskState *next; + int used; /* non zero if used */ +-#if 1 ++ long ts_tid; /* tid (or pid) of this task */ + #ifdef TARGET_ARM + int swi_errno; + #endif +@@ -90,7 +90,6 @@ typedef struct TaskState { + uint32_t heap_limit; + #endif + uint32_t stack_base; +-#endif + struct image_info *info; + struct bsd_binprm *bprm; + +diff --git a/bsd-user/signal.c b/bsd-user/signal.c +index 52441c4..d56837b 100644 +--- a/bsd-user/signal.c ++++ b/bsd-user/signal.c +@@ -31,7 +31,7 @@ + #include "qemu.h" + #include "target_signal.h" + +-//#define DEBUG_SIGNAL ++// #define DEBUG_SIGNAL + + #ifndef _NSIG + #define _NSIG 128 +@@ -606,101 +606,31 @@ do_sigaction(int sig, const struct target_sigaction *act, + return (ret); + } + +-#if defined(TARGET_MIPS64) +-static inline int +-restore_sigmcontext(CPUMIPSState *regs, target_mcontext_t *mc) +-{ +- int i, err = 0; +- +- for(i = 1; i < 32; i++) +- err |= __get_user(regs->active_tc.gpr[i], +- &mc->mc_regs[i]); +- err |= __get_user(regs->CP0_EPC, &mc->mc_pc); +- err |= __get_user(regs->active_tc.LO[0], &mc->mullo); +- err |= __get_user(regs->active_tc.HI[0], &mc->mulhi); +- err |= __get_user(regs->tls_value, &mc->mc_tls); /* XXX thread tls */ +- +-#if 0 /* XXX */ +- int used_fp = 0; +- +- err |= __get_user(used_fp, &mc->mc_fpused); +- conditional_used_math(used_fp); +- +- preempt_disabled(); +- if (used_math()) { +- /* restore fpu context if we have used it before */ +- own_fpu(); +- err |= restore_fp_context(mc); +- } else { +- /* signal handler may have used FPU. Give it up. */ +- lose_fpu(); +- } +- preempt_enable(); +-#endif +- +- return (err); +-} +- +-static inline int +-setup_sigmcontext(CPUMIPSState *regs, target_mcontext_t *mc, int32_t oonstack) +-{ +- int i, err = 0; +- abi_long ucontext_magic = TARGET_UCONTEXT_MAGIC; +- +- err = __put_user(oonstack ? 1 : 0, &mc->mc_onstack); +- err |= __put_user(regs->active_tc.PC, &mc->mc_pc); +- err |= __put_user(regs->active_tc.LO[0], &mc->mullo); +- err |= __put_user(regs->active_tc.HI[0], &mc->mulhi); +- err |= __put_user(regs->tls_value, &mc->mc_tls); /* XXX thread tls */ +- +- err |= __put_user(ucontext_magic, &mc->mc_regs[0]); +- for(i = 1; i < 32; i++) +- err |= __put_user(regs->active_tc.gpr[i], &mc->mc_regs[i]); +- +- err |= __put_user(0, &mc->mc_fpused); +- +-#if 0 /* XXX */ +- err |= __put_user(used_math(), &mc->mc_fpused); +- if (used_math()) +- goto out; +- +- /* +- * Save FPU state to signal context. Signal handler will "inherit" +- * current FPU state. +- */ +- preempt_disable(); +- +- if (!is_fpu_owner()) { +- own_fpu(); +- for(i = 0; i < 33; i++) +- err |= __put_user(regs->active_tc.fpregs[i], &mc->mc_fpregs[i]); +- } +- err |= save_fp_context(fg); +- +- preempt_enable(); +-out: +-#endif +- return (err); +-} ++#if defined(TARGET_MIPS) || defined(TARGET_SPARC64) + + static inline abi_ulong +-get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) ++get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) + { + abi_ulong sp; + + /* Use default user stack */ +- sp = regs->active_tc.gpr[29]; ++ sp = get_sp_from_cpustate(regs); + + if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { +- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; ++ sp = target_sigaltstack_used.ss_sp + ++ target_sigaltstack_used.ss_size; + } + ++#if defined(TARGET_MIPS) + return ((sp - frame_size) & ~7); ++#else ++ return (sp - frame_size); ++#endif + } + +-/* compare to mips/mips/pm_machdep.c sendsig() */ ++/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */ + static void setup_frame(int sig, struct target_sigaction *ka, +- target_sigset_t *set, CPUMIPSState *regs) ++ target_sigset_t *set, CPUArchState *regs) + { + struct target_sigframe *frame; + abi_ulong frame_addr; +@@ -709,54 +639,36 @@ static void setup_frame(int sig, struct target_sigaction *ka, + #ifdef DEBUG_SIGNAL + fprintf(stderr, "setup_frame()\n"); + #endif ++#if defined(TARGET_SPARC64) ++ if (!sparc_user_sigtramp) { ++ /* No signal trampoline... kill the process. */ ++ fprintf(stderr, "setup_frame(): no sigtramp\n"); ++ force_sig(TARGET_SIGKILL); ++ } ++#endif + + frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto give_sigsegv; + +- if (setup_sigmcontext(regs, &frame->sf_uc.uc_mcontext, +- ! on_sig_stack(frame_addr))) ++#if defined(TARGET_MIPS) ++ int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC : ++ TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC; ++#else ++ int mflags = 0; ++#endif ++ if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) + goto give_sigsegv; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { +- if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) ++ if (__put_user(set->__bits[i], ++ &frame->sf_uc.uc_sigmask.__bits[i])) + goto give_sigsegv; + } + +- /* fill in sigframe structure */ +- if (__put_user(sig, &frame->sf_signum)) +- goto give_sigsegv; +- if (__put_user(0, &frame->sf_siginfo)) +- goto give_sigsegv; +- if (__put_user(0, &frame->sf_ucontext)) ++ if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) + goto give_sigsegv; + +- /* fill in siginfo structure */ +- if (__put_user(sig, &frame->sf_si.si_signo)) +- goto give_sigsegv; +- if (__put_user(TARGET_SA_SIGINFO, &frame->sf_si.si_code)) +- goto give_sigsegv; +- if (__put_user(regs->CP0_BadVAddr, &frame->sf_si.si_addr)) +- goto give_sigsegv; +- +- /* +- * Arguments to signal handler: +- * a0 ($4) = signal number +- * a1 ($5) = siginfo pointer +- * a2 ($6) = ucontext pointer +- * PC = signal handler pointer +- * t9 ($25) = signal handler pointer +- * $29 = point to sigframe struct +- * ra ($31) = sigtramp at base of user stack +- */ +- regs->active_tc.gpr[ 4] = sig; +- regs->active_tc.gpr[ 5] = frame_addr + +- offsetof(struct target_sigframe, sf_si); +- regs->active_tc.gpr[ 6] = frame_addr + +- offsetof(struct target_sigframe, sf_uc); +- regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; +- regs->active_tc.gpr[29] = frame_addr; +- regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; + unlock_user_struct(frame, frame_addr, 1); + return; + +@@ -766,7 +678,7 @@ give_sigsegv: + } + + long +-do_sigreturn(CPUMIPSState *regs, abi_ulong uc_addr) ++do_sigreturn(CPUArchState *regs, abi_ulong uc_addr) + { + target_ucontext_t *ucontext; + sigset_t blocked; +@@ -784,14 +696,17 @@ do_sigreturn(CPUMIPSState *regs, abi_ulong uc_addr) + goto badframe; + } + +- if (restore_sigmcontext(regs, &ucontext->uc_mcontext)) ++ if (set_mcontext(regs, &ucontext->uc_mcontext, 0)) + goto badframe; + + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); + +- regs->active_tc.PC = regs->CP0_EPC; +- regs->CP0_EPC = 0; /* XXX for nested signals ? */ ++#if defined(TARGET_MIPS) ++ CPUMIPSState *mips_regs = (CPUMIPSState *)regs; ++ mips_regs->active_tc.PC = mips_regs->CP0_EPC; ++ mips_regs->CP0_EPC = 0; /* XXX for nested signals ? */ ++#endif + return (-TARGET_QEMU_ESIGRETURN); + + badframe: +@@ -799,9 +714,10 @@ badframe: + return (0); + } + +-#elif defined(TARGET_SPARC64) + +-extern abi_ulong sparc_user_sigtramp; ++ ++/* #elif defined(TARGET_SPARC64) */ ++#if 0 + + #define mc_flags mc_global[0] + #define mc_sp mc_out[6] +@@ -1039,6 +955,7 @@ badframe: + force_sig(TARGET_SIGSEGV); + return (0); + } ++#endif + + #else + +diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h +index 79dfc1e..e2fe79c 100644 +--- a/bsd-user/sparc/target_signal.h ++++ b/bsd-user/sparc/target_signal.h +@@ -13,9 +13,34 @@ + #define TARGET_MINSIGSTKSZ (512 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + ++typedef target_ulong target_mcontext_t; /* dummy */ ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ + static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) + { + return state->regwptr[UREG_FP]; + } + ++static inline int ++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "SPARC doesn't have support for get_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ ++static inline int ++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "SPARC doesn't have support for set_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h +index d3e58bb..1bc7c96 100644 +--- a/bsd-user/sparc64/target_signal.h ++++ b/bsd-user/sparc64/target_signal.h +@@ -10,12 +10,239 @@ + #define UREG_FP UREG_I6 + #endif + ++#define mc_flags mc_global[0] ++#define mc_sp mc_out[6] ++#define mc_fprs mc_local[0] ++#define mc_fsr mc_local[1] ++#define mc_gsr mc_local[2] ++#define mc_tnpc mc_in[0] ++#define mc_tpc mc_in[1] ++#define mc_tstate mc_in[2] ++#define mc_y mc_in[4] ++#define mc_wstate mc_in[5] ++ ++#define ureg_i0 regwptr[0 ] ++#define ureg_i1 regwptr[1 ] ++#define ureg_i2 regwptr[2 ] ++#define ureg_i3 regwptr[3 ] ++#define ureg_i4 regwptr[4 ] ++#define ureg_i5 regwptr[5 ] ++#define ureg_i6 regwptr[6 ] ++#define ureg_i7 regwptr[7 ] ++#define ureg_l0 regwptr[8 ] ++#define ureg_l1 regwptr[9 ] ++#define ureg_l2 regwptr[10] ++#define ureg_l3 regwptr[11] ++#define ureg_l4 regwptr[12] ++#define ureg_l5 regwptr[13] ++#define ureg_l6 regwptr[14] ++#define ureg_l7 regwptr[15] ++#define ureg_o0 regwptr[16] ++#define ureg_o1 regwptr[17] ++#define ureg_o2 regwptr[18] ++#define ureg_o3 regwptr[19] ++#define ureg_o4 regwptr[20] ++#define ureg_o5 regwptr[21] ++#define ureg_o6 regwptr[22] ++#define ureg_o7 regwptr[23] ++#define ureg_fp ureg_i6 ++#define ureg_sp ureg_o6 ++#define ureg_fprs fprs ++#define ureg_fsr fsr ++#define ureg_gsr gsr ++#define ureg_tnpc npc ++#define ureg_tpc pc ++#define ureg_y y ++ ++#define TARGET_FPRS_FEF (1 << 2) ++#define TARGET_MC_VERSION 1L ++ + #define TARGET_MINSIGSTKSZ (1024 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + +-static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) ++#define TARGET_STACK_BIAS 2047 /* AKA. SPOFF */ ++ ++struct target_mcontext { ++ uint64_t mc_global[8]; ++ uint64_t mc_out[8]; ++ uint64_t mc_local[8]; ++ uint64_t mc_in[8]; ++ uint32_t mc_fp[64]; ++} __aligned(64); ++ ++typedef struct target_mcontext target_mcontext_t; ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ ++struct target_sigframe { ++ target_ucontext_t sf_uc; ++ target_siginfo_t sf_si; ++}; ++ ++extern abi_ulong sparc_user_sigtramp; ++ ++static inline int ++set_sigtramp_args(CPUSPARCState *regs, int sig, struct target_sigframe *frame, ++ abi_ulong frame_addr, struct target_sigaction *ka) + { ++ ++ frame->sf_si.si_signo = sig; ++ frame->sf_si.si_code = TARGET_SA_SIGINFO; ++ ++ /* Arguments to signal handler: ++ * ++ * i0 = signal number ++ * i1 = pointer to siginfo struct ++ * i2 = pointer to ucontext struct ++ * i3 = (not used in new style) ++ * i4 = signal handler address (called by sigtramp) ++ */ ++ regs->ureg_i0 = sig; ++ regs->ureg_i1 = frame_addr + ++ offsetof(struct target_sigframe, sf_si); ++ regs->ureg_i2 = frame_addr + ++ offsetof(struct target_sigframe, sf_uc); ++ /* env->ureg_o3 used in the Old FreeBSD-style arguments. */ ++ regs->ureg_i4 = ka->_sa_handler; ++ regs->ureg_tpc = sparc_user_sigtramp; ++ regs->ureg_tnpc = (regs->ureg_tpc + 4); ++ regs->ureg_sp = frame_addr - TARGET_STACK_BIAS; ++ ++ return (0); ++} ++ ++static inline abi_ulong ++get_sp_from_cpustate(CPUSPARCState *state) ++{ ++ + return state->regwptr[UREG_FP]; + } + ++/* compare to sparc64/sparc64/machdep.c get_mcontext() */ ++static inline int ++get_mcontext(CPUSPARCState *regs, target_mcontext_t *mcp, int flags) ++{ ++ ++ /* Skip over the trap instruction, first. */ ++ regs->pc = regs->npc; ++ regs->npc += 4; ++ ++ mcp->mc_flags = TARGET_MC_VERSION; /* mc_global[0] */ ++ mcp->mc_global[1] = tswapal(regs->gregs[1]); ++ mcp->mc_global[2] = tswapal(regs->gregs[2]); ++ mcp->mc_global[3] = tswapal(regs->gregs[3]); ++ mcp->mc_global[4] = tswapal(regs->gregs[4]); ++ mcp->mc_global[5] = tswapal(regs->gregs[5]); ++ mcp->mc_global[6] = tswapal(regs->gregs[6]); ++ /* skip %g7 since it is used as the userland TLS register */ ++ ++ if (flags & TARGET_MC_GET_CLEAR_RET) { ++ mcp->mc_out[0] = 0; ++ mcp->mc_out[1] = 0; ++ } else { ++ mcp->mc_out[0] = tswapal(regs->ureg_i0); ++ mcp->mc_out[1] = tswapal(regs->ureg_i1); ++ } ++ mcp->mc_out[2] = tswapal(regs->ureg_i2); ++ mcp->mc_out[3] = tswapal(regs->ureg_i3); ++ mcp->mc_out[4] = tswapal(regs->ureg_i4); ++ mcp->mc_out[5] = tswapal(regs->ureg_i5); ++ mcp->mc_out[6] = tswapal(regs->ureg_i6); ++ mcp->mc_out[7] = tswapal(regs->ureg_i7); ++ ++ mcp->mc_fprs = tswapal(regs->fprs); /* mc_local[0] */ ++ mcp->mc_fsr = tswapal(regs->fsr); /* mc_local[1] */ ++ mcp->mc_gsr = tswapal(regs->gsr); /* mc_local[2] */ ++ ++ mcp->mc_tnpc = tswapal(regs->npc); /* mc_in[0] */ ++ mcp->mc_tpc = tswapal(regs->pc); /* mc_in[1] */ ++#if 0 ++ mcp->mc_tstate = tswapal(regs->ureg_tstate); /* mc_in[2] */ ++#else ++ abi_ulong cwp64 = cpu_get_cwp64(regs); ++ abi_ulong ccr = cpu_get_ccr(regs) << 32; ++ abi_ulong asi = (regs->asi & 0xff) << 24; ++ mcp->mc_tstate = tswapal(ccr | asi | cwp64); ++#endif ++ ++ mcp->mc_y = tswapal(regs->y); /* mc_in[4] */ ++ ++ /* XXX ++ if ((regs->ureg_l0 & TARGET_FPRS_FEF) != 0) { ++ int i; ++ ++ for(i = 0; i < 64; i++) ++ mcp->mc_fp[i] = tswapal(regs->fpr[i]); ++ } ++ */ ++ ++ return (0); ++} ++ ++extern void helper_flushw(CPUSPARCState *env); ++ ++/* compare to sparc64/sparc64/machdep.c set_mcontext() */ ++static inline int ++set_mcontext(CPUSPARCState *regs, target_mcontext_t *mcp, int flags) ++{ ++ /* XXX need to add version check here. */ ++ ++ /* Make sure the windows are spilled first. */ ++ helper_flushw(regs); ++ ++ regs->gregs[1] = tswapal(mcp->mc_global[1]); ++ regs->gregs[2] = tswapal(mcp->mc_global[2]); ++ regs->gregs[3] = tswapal(mcp->mc_global[3]); ++ regs->gregs[4] = tswapal(mcp->mc_global[4]); ++ regs->gregs[5] = tswapal(mcp->mc_global[5]); ++ regs->gregs[6] = tswapal(mcp->mc_global[6]); ++ ++ regs->ureg_i0 = tswapal(mcp->mc_out[0]); ++ regs->ureg_i1 = tswapal(mcp->mc_out[1]); ++ regs->ureg_i2 = tswapal(mcp->mc_out[2]); ++ regs->ureg_i3 = tswapal(mcp->mc_out[3]); ++ regs->ureg_i4 = tswapal(mcp->mc_out[4]); ++ regs->ureg_i5 = tswapal(mcp->mc_out[5]); ++ regs->ureg_i6 = tswapal(mcp->mc_out[6]); ++ regs->ureg_i7 = tswapal(mcp->mc_out[7]); ++ ++ regs->fprs = tswapal(mcp->mc_fprs); /* mc_local[0] */ ++ regs->fsr = tswapal(mcp->mc_fsr); /* mc_local[1] */ ++ regs->gsr = tswapal(mcp->mc_gsr); /* mc_local[2] */ ++ ++ regs->npc = tswapal(mcp->mc_tnpc); /* mc_in[0] */ ++ regs->pc = tswapal(mcp->mc_tpc); /* mc_in[1] */ ++ ++#if 0 ++ regs->ureg_tstate = tswapal(mcp->mc_tstate); /* mc_in[2] */ ++#else ++ abi_ulong tstate = tswapal(mcp->mc_tstate); /* mc_in[2] */ ++ ++ regs->asi = (tstate >> 24) & 0xff; ++ cpu_put_ccr(regs, tstate >> 32); ++ cpu_put_cwp64(regs, tstate & 0x1f); ++ ++#endif ++ regs->ureg_y = tswapal(mcp->mc_y); /* mc_in[4] */ ++ ++ /* XXX ++ if ((regs->ureg_fprs & TARGET_FPRS_FEF) != 0) { ++ int i; ++ ++ regs->ureg_l0 = 0; ++ for(i = 0; i < 64; i++) ++ regs->fpr[i] = tswapal(mcp->mc_fp[i]); ++ } ++ */ ++ ++ return (0); ++} ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index 625c3cf..4deb0db 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -43,6 +43,12 @@ + #ifdef __FreeBSD__ + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include + #endif + #include + #include +@@ -251,7 +257,24 @@ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + #ifdef TARGET_MIPS + static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + { +- return -TARGET_EINVAL; ++ int ret = 0; ++ CPUMIPSState *mips_env = (CPUMIPSState *)env; ++ ++ switch(op) { ++ case TARGET_MIPS_SET_TLS: ++ if (get_user(mips_env->tls_value, parms, abi_ulong)) ++ ret = -TARGET_EFAULT; ++ break; ++ case TARGET_MIPS_GET_TLS: ++ if (put_user(mips_env->tls_value, parms, abi_ulong)) ++ ret = -TARGET_EFAULT; ++ break; ++ default: ++ ret = -TARGET_EINVAL; ++ break; ++ } ++ ++ return (ret); + } + #endif + +@@ -2119,6 +2142,383 @@ do_fork(CPUArchState *env, int num, int flags, int *fdp) + return (ret); + } + ++#if defined(CONFIG_USE_NPTL) ++ ++#define NEW_STACK_SIZE (0x40000) ++ ++static pthread_mutex_t new_thread_lock = PTHREAD_MUTEX_INITIALIZER; ++typedef struct { ++ CPUArchState *env; ++ long tid; ++ pthread_mutex_t mutex; ++ pthread_cond_t cond; ++ pthread_t thread; ++ sigset_t sigmask; ++ struct target_thr_param param; ++} new_thread_info_t; ++ ++static void * ++new_thread_start(void *arg) ++{ ++ new_thread_info_t *info = arg; ++ CPUArchState *env; ++ TaskState *ts; ++ long tid; ++ ++ env = info->env; ++ thread_env = env; ++ ts = (TaskState *)thread_env->opaque; ++ (void)thr_self(&tid); ++ info->tid = tid; ++ task_settid(ts); ++ ++ /* copy out the TID info */ ++ if (info->param.child_tid) ++ put_user(tid, info->param.child_tid, abi_long); ++ if (info->param.parent_tid) ++ put_user(tid, info->param.parent_tid, abi_long); ++ ++#ifdef TARGET_MIPS64 ++ CPUMIPSState *regs = env; ++ regs->active_tc.gpr[25] = regs->active_tc.PC = info->param.start_func; ++ regs->active_tc.gpr[ 4] = info->param.arg; ++ regs->active_tc.gpr[29] = info->param.stack_base; ++#endif ++ /* Eenable signals */ ++ sigprocmask(SIG_SETMASK, &info->sigmask, NULL); ++ /* Signal to the parent that we're ready. */ ++ pthread_mutex_lock(&info->mutex); ++ pthread_cond_broadcast(&info->cond); ++ pthread_mutex_unlock(&info->mutex); ++ /* Wait until the parent has finished initializing the TLS state. */ ++ pthread_mutex_lock(&new_thread_lock); ++ pthread_mutex_unlock(&new_thread_lock); ++ ++ cpu_loop(env); ++ /* never exits */ ++ ++ return (NULL); ++} ++ ++static void ++rtp_to_schedparam(const struct rtprio *rtp, int *policy, struct sched_param *param) ++{ ++ ++ switch(rtp->type) { ++ case RTP_PRIO_REALTIME: ++ *policy = SCHED_RR; ++ param->sched_priority = RTP_PRIO_MAX - rtp->prio; ++ break; ++ ++ case RTP_PRIO_FIFO: ++ *policy = SCHED_FIFO; ++ param->sched_priority = RTP_PRIO_MAX - rtp->prio; ++ break; ++ ++ default: ++ *policy = SCHED_OTHER; ++ param->sched_priority = 0; ++ break; ++ } ++} ++ ++static int ++do_thr_create(CPUArchState *env, ucontext_t *ctx, long *id, int flags) ++{ ++ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_create)); ++} ++ ++static int ++do_thr_new(CPUArchState *env, abi_ulong target_param_addr, int32_t param_size) ++{ ++ new_thread_info_t info; ++ pthread_attr_t attr; ++ TaskState *ts; ++ CPUArchState *new_env; ++ struct target_thr_param *target_param; ++ abi_ulong target_rtp_addr; ++ struct target_rtprio *target_rtp; ++ struct rtprio *rtp_ptr, rtp; ++ TaskState *parent_ts = (TaskState *)env->opaque; ++ sigset_t sigmask; ++ struct sched_param sched_param; ++ int sched_policy; ++ int ret = 0; ++ ++ memset(&info, 0, sizeof(info)); ++ ++ if (!lock_user_struct(VERIFY_READ, target_param, target_param_addr, 1)) ++ return (-TARGET_EFAULT); ++ info.param.start_func = tswapal(target_param->start_func); ++ info.param.arg = tswapal(target_param->arg); ++ info.param.stack_base = tswapal(target_param->stack_base); ++ info.param.stack_size = tswapal(target_param->stack_size); ++ info.param.tls_base = tswapal(target_param->tls_base); ++ info.param.tls_size = tswapal(target_param->tls_size); ++ info.param.child_tid = tswapal(target_param->child_tid); ++ info.param.parent_tid = tswapal(target_param->parent_tid); ++ target_rtp_addr = info.param.rtp = tswapal(target_param->rtp); ++ unlock_user(target_param, target_param_addr, 0); ++ ++ if (target_rtp_addr) { ++ if (!lock_user_struct(VERIFY_READ, target_rtp, target_rtp_addr, ++ 1)) ++ return (-TARGET_EFAULT); ++ rtp.type = tswap16(target_rtp->type); ++ rtp.prio = tswap16(target_rtp->prio); ++ unlock_user(target_rtp, target_rtp_addr, 0); ++ rtp_ptr = &rtp; ++ } else { ++ rtp_ptr = NULL; ++ } ++ ++ /* Create a new CPU instance. */ ++ ts = g_malloc0(sizeof(TaskState)); ++ init_task_state(ts); ++ new_env = cpu_copy(env); ++#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) ++ cpu_reset(ENV_GET_CPU(new_env)); ++#endif ++ ++ /* init regs that differ from the parent thread. */ ++ cpu_clone_regs(new_env, info.param.stack_base); ++ new_env->opaque = ts; ++ ts->bprm = parent_ts->bprm; ++ ts->info = parent_ts->info; ++ ++#if defined(TARGET_MIPS) ++ env->tls_value = info.param.tls_base; ++ /* cpu_set_tls(new_env, info.param.tls_base); */ ++#endif ++ ++ /* Grab a mutex so that thread setup appears atomic. */ ++ pthread_mutex_lock(&new_thread_lock); ++ ++ pthread_mutex_init(&info.mutex, NULL); ++ pthread_mutex_lock(&info.mutex); ++ pthread_cond_init(&info.cond, NULL); ++ info.env = new_env; ++ ++ /* XXX return value needs to be checked... */ ++ pthread_attr_init(&attr); ++ pthread_attr_setstacksize(&attr, NEW_STACK_SIZE); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ if (rtp_ptr) { ++ rtp_to_schedparam(&rtp, &sched_policy, &sched_param); ++ pthread_attr_setschedpolicy(&attr, sched_policy); ++ pthread_attr_setschedparam(&attr, &sched_param); ++ } ++ ++ /* ++ * It is not safe to deliver signals until the child has finished ++ * initializing, so temporarily block all signals. ++ */ ++ sigfillset(&sigmask); ++ sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask); ++ ++ /* XXX return value needs to be checked... */ ++ ret = pthread_create(&info.thread, &attr, new_thread_start, &info); ++ /* XXX Free new CPU state if thread creation fails. */ ++ ++ sigprocmask(SIG_SETMASK, &info.sigmask, NULL); ++ pthread_attr_destroy(&attr); ++ if (0 == ret) { ++ /* Wait for the child to initialize. */ ++ pthread_cond_wait(&info.cond, &info.mutex); ++ } else { ++ /* pthread_create failed. */ ++ } ++ ++ pthread_mutex_unlock(&info.mutex); ++ pthread_cond_destroy(&info.cond); ++ pthread_mutex_destroy(&info.mutex); ++ pthread_mutex_unlock(&new_thread_lock); ++ ++ return (ret); ++} ++ ++static int ++do_thr_self(long *id) ++{ ++ ++ return (get_errno(thr_self(id))); ++} ++ ++static void ++do_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr) ++{ ++ ++ if (first_cpu->next_cpu) { ++ TaskState *ts; ++ CPUArchState **lastp, *p; ++ ++ /* ++ * *XXX This probably breaks if a signal arrives. ++ * We should disable signals. ++ */ ++ cpu_list_lock(); ++ lastp = &first_cpu; ++ p = first_cpu; ++ while (p && p != (CPUArchState *)cpu_env) { ++ lastp = &p->next_cpu; ++ p = p->next_cpu; ++ } ++ /* ++ * if we didn't find the CPU for this thread then something ++ * is horribly wrong. ++ */ ++ if (!p) ++ abort(); ++ /* Remove the CPU from the list. */ ++ *lastp = p->next_cpu; ++ cpu_list_unlock(); ++ ts = ((CPUArchState *)cpu_env)->opaque; ++ ++ if (tid_addr) { ++ /* Signal target userland that it can free the stack. */ ++ if (! put_user_u32(1, tid_addr)) ++ _umtx_op(g2h(tid_addr), UMTX_OP_WAKE, INT_MAX, ++ NULL, NULL); ++ } ++ ++ thread_env = NULL; ++ object_delete(OBJECT(ENV_GET_CPU(cpu_env))); ++ g_free(ts); ++ pthread_exit(NULL); ++ } ++} ++ ++static int ++do_thr_kill(long id, int sig) ++{ ++ ++ return (get_errno(thr_kill(id, sig))); ++} ++ ++static int ++do_thr_kill2(pid_t pid, long id, int sig) ++{ ++ ++ return (get_errno(thr_kill2(pid, id, sig))); ++} ++ ++static int ++do_thr_suspend(const struct timespec *timeout) ++{ ++ ++ return (get_errno(thr_suspend(timeout))); ++} ++ ++static int ++do_thr_wake(long tid) ++{ ++ ++ return (get_errno(thr_wake(tid))); ++} ++ ++static int ++do_thr_set_name(long tid, char *name) ++{ ++ ++ return (get_errno(thr_set_name(tid, name))); ++} ++ ++ ++#else /* ! CONFIG_USE_NPTL */ ++ ++static int ++do_thr_create(CPUArchState *env, ucontext_t *ctx, long *id, int flags) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_create)); ++} ++ ++static int ++do_thr_new(CPUArchState *env, abi_ulong target_param_addr, int32_t param_size) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_new)); ++} ++ ++static int ++do_thr_self(long *tid) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_self)); ++} ++ ++static void ++do_thr_exit(CPUArchState *cpu_env, abi_ulong state_addr) ++{ ++} ++ ++static int ++do_thr_kill(long tid, int sig) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_kill2)); ++} ++ ++static int ++do_thr_kill2(pid_t pid, long tid, int sig) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_kill2)); ++} ++ ++static int ++do_thr_suspend(const struct timespec *timeout) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_suspend)); ++} ++ ++static int ++do_thr_wake(long tid) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_wake)); ++} ++ ++static int ++do_thr_set_name(long tid, char *name) ++{ ++ return (unimplemented(TARGET_FREEBSD_NR_thr_set_name)); ++} ++ ++#endif /* CONFIG_USE_NPTL */ ++ ++static int ++do_umtx_lock(abi_ulong umtx_addr, uint32_t id) ++{ ++ int ret = 0; ++ ++ for (;;) { ++ ret = get_errno(_umtx_op(g2h(umtx_addr + ++ offsetof(struct target_umtx, u_owner)), ++ UMTX_OP_MUTEX_WAIT, UMTX_UNOWNED, 0, 0)); ++ if (ret) ++ return (ret); ++ if (atomic_cmpset_acq_32(g2h(umtx_addr + ++ offsetof(struct target_umtx, u_owner)), ++ UMTX_UNOWNED, id)) ++ return (0); ++ } ++} ++ ++static int ++do_umtx_unlock(abi_ulong umtx_addr, uint32 id) ++{ ++ uint32_t owner; ++ ++ do { ++ if (get_user_u32(owner, umtx_addr + ++ offsetof(struct target_umtx, u_owner))) ++ return (-TARGET_EFAULT); ++ if (owner != id) ++ return (-TARGET_EPERM); ++ } while (!atomic_cmpset_rel_32(g2h(umtx_addr + ++ offsetof(struct target_umtx, u_owner)), owner, ++ UMUTEX_UNOWNED)); ++ ++ return (0); ++} ++ ++ + /* do_syscall() should always have a single exit point at the end so + that actions, such as logging of syscall results, can be performed. + All errnos that do_syscall() returns must be -TARGET_. */ +@@ -4091,6 +4491,23 @@ do_stat: + break; + #endif + ++#ifdef TARGET_FREEBSD_NR_getdomainname ++ case TARGET_FREEBSD_NR_getdomainname: ++ ret = unimplemented(num); ++ break; ++#endif ++#ifdef TARGET_FREEBSD_NR_setdomainname ++ case TARGET_FREEBSD_NR_setdomainname: ++ ret = unimplemented(num); ++ break; ++#endif ++#ifdef TARGET_FREEBSD_NR_uname ++ case TARGET_FREEBSD_NR_uname: ++ ret = unimplemented(num); ++ break; ++#endif ++ ++ + #if 0 /* XXX not supported in libc yet, it seems (10.0 addition). */ + case TARGET_FREEBSD_NR_posix_fadvise: + { +@@ -4136,6 +4553,211 @@ do_stat: + break; + #endif + ++ case TARGET_FREEBSD_NR_thr_new: ++ ret = do_thr_new(cpu_env, arg1, arg2); ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_create: ++ { ++ ucontext_t ucxt; ++ long tid; ++ ++ ret = do_thr_create(cpu_env, &ucxt, &tid, arg3); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_set_name: ++ if (!(p = lock_user_string(arg2))) ++ goto efault; ++ ret = do_thr_set_name(arg1, p); ++ unlock_user(p, arg2, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_self: ++ { ++ long tid; ++ ++ if ((ret = do_thr_self(&tid)) == 0) { ++ if (put_user((abi_long)tid, arg1, abi_long)) ++ goto efault; ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_suspend: ++ { ++ struct timespec ts; ++ ++ if (target_to_host_timespec(&ts, arg1)) ++ goto efault; ++ ++ ret = do_thr_suspend(&ts); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_wake: ++ ret = do_thr_wake(arg1); ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_kill: ++ ret = do_thr_kill(arg1, arg2); ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_kill2: ++ ret = do_thr_kill2(arg1, arg2, arg3); ++ break; ++ ++ case TARGET_FREEBSD_NR_thr_exit: ++ ret = 0; /* suspress compile warning */ ++ do_thr_exit(cpu_env, arg1); ++ /* Shouldn't be reached. */ ++ break; ++ ++ case TARGET_FREEBSD_NR_rtprio_thread: ++ ret = 0; ++ break; ++ ++ case TARGET_FREEBSD_NR_getcontext: ++ { ++ target_ucontext_t *ucp; ++ sigset_t sigmask; ++ ++ if (0 == arg1) { ++ ret = -TARGET_EINVAL; ++ } else { ++ ret = get_errno(sigprocmask(0, NULL, &sigmask)); ++ if (!is_error(ret)) { ++ if (!(ucp = lock_user(VERIFY_WRITE, arg1, ++ sizeof(target_ucontext_t), 0))) ++ goto efault; ++ ret = get_mcontext(cpu_env, &ucp->uc_mcontext, ++ TARGET_MC_GET_CLEAR_RET); ++ host_to_target_sigset(&ucp->uc_sigmask, ++ &sigmask); ++ memset(ucp->__spare__, 0, ++ sizeof(ucp->__spare__)); ++ unlock_user(ucp, arg1, ++ sizeof(target_ucontext_t)); ++ } ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_setcontext: ++ { ++ target_ucontext_t *ucp; ++ sigset_t sigmask; ++ ++ if (0 == arg1) { ++ ret = -TARGET_EINVAL; ++ } else { ++ if (!(ucp = lock_user(VERIFY_READ, arg1, ++ sizeof(target_ucontext_t), 1))) ++ goto efault; ++ ret = set_mcontext(cpu_env, &ucp->uc_mcontext, 0); ++ target_to_host_sigset(&sigmask, &ucp->uc_sigmask); ++ unlock_user(ucp, arg1, sizeof(target_ucontext_t)); ++ if (0 == ret) ++ (void)sigprocmask(SIG_SETMASK, &sigmask, NULL); ++ } ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR_swapcontext: ++ /* ++ * XXX Does anything besides old implementations of ++ * setjmp()/longjmp() uses these? ++ */ ++ ret = unimplemented(num); ++ break; ++ ++ case TARGET_FREEBSD_NR__umtx_lock: ++ { ++ long tid; ++ ++ thr_self(&tid); ++ ret = do_umtx_lock(arg1, tswap32(tid)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR__umtx_unlock: ++ { ++ long tid; ++ ++ thr_self(&tid); ++ ret = do_umtx_unlock(arg1, tswap32(tid)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR__umtx_op: ++ { ++ struct timespec ts; ++ void *object = NULL; ++ int operation; ++ void *addr = NULL; ++ void *addr2 = NULL; ++ ++ ++ /* int _umtx_op(void *obj, int op, u_long val, ++ * void *uaddr, void *uaddr2); */ ++ ++ abi_ulong obj = arg1; ++ int op = (int)arg2; ++ u_long val = arg3; ++ /* abi_ulong uaddr = arg4; */ ++ abi_ulong uaddr2 = arg5; ++ ++ switch(op) { ++ case TARGET_UMTX_OP_LOCK: ++ ret = do_umtx_lock(obj, tswap32((uint32_t)val)); ++ break; ++ ++ case TARGET_UMTX_OP_UNLOCK: ++ ret = do_umtx_unlock(obj, tswap32((uint32_t)val)); ++ break; ++ ++ case TARGET_UMTX_OP_WAIT: ++ if (uaddr2) { ++ if (target_to_host_timespec(&ts, uaddr2)) ++ goto efault; ++ addr2 = (void *)&ts; ++ } ++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_WAIT, ++ tswap32(val), addr, addr2)); ++ break; ++ ++ case TARGET_UMTX_OP_WAKE: ++ operation = UMTX_OP_WAKE; ++ object = g2h(obj); ++ ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_WAKE, ++ val, 0, 0)); ++ break; ++ ++ case TARGET_UMTX_OP_MUTEX_TRYLOCK: ++ case TARGET_UMTX_OP_MUTEX_LOCK: ++ case TARGET_UMTX_OP_MUTEX_UNLOCK: ++ case TARGET_UMTX_OP_SET_CEILING: ++ case TARGET_UMTX_OP_CV_WAIT: ++ case TARGET_UMTX_OP_CV_SIGNAL: ++ case TARGET_UMTX_OP_CV_BROADCAST: ++ case TARGET_UMTX_OP_WAIT_UINT: ++ case TARGET_UMTX_OP_RW_RDLOCK: ++ case TARGET_UMTX_OP_RW_WRLOCK: ++ case TARGET_UMTX_OP_RW_UNLOCK: ++ case TARGET_UMTX_OP_WAIT_UINT_PRIVATE: ++ case TARGET_UMTX_OP_WAKE_PRIVATE: ++ case TARGET_UMTX_OP_MUTEX_WAIT: ++ case TARGET_UMTX_OP_MUTEX_WAKE: ++ case TARGET_UMTX_OP_SEM_WAIT: ++ case TARGET_UMTX_OP_SEM_WAKE: ++ case TARGET_UMTX_OP_NWAKE_PRIVATE: ++ default: ++ ret = -TARGET_EINVAL; ++ break; ++ } ++ } ++ break; ++ + case TARGET_FREEBSD_NR_yield: + case TARGET_FREEBSD_NR_sched_setparam: + case TARGET_FREEBSD_NR_sched_getparam: +@@ -4146,36 +4768,18 @@ do_stat: + case TARGET_FREEBSD_NR_sched_get_priority_min: + case TARGET_FREEBSD_NR_sched_rr_get_interval: + +- + case TARGET_FREEBSD_NR_reboot: + case TARGET_FREEBSD_NR_shutdown: + + case TARGET_FREEBSD_NR_swapon: + case TARGET_FREEBSD_NR_swapoff: + +- case TARGET_FREEBSD_NR_thr_create: +- case TARGET_FREEBSD_NR_thr_exit: +- case TARGET_FREEBSD_NR_thr_self: +- case TARGET_FREEBSD_NR_thr_suspend: +- case TARGET_FREEBSD_NR_thr_wake: +- case TARGET_FREEBSD_NR_thr_new: +- case TARGET_FREEBSD_NR_thr_set_name: +- case TARGET_FREEBSD_NR_thr_kill2: +- +- case TARGET_FREEBSD_NR_getcontext: +- case TARGET_FREEBSD_NR_setcontext: +- case TARGET_FREEBSD_NR_swapcontext: +- +- case TARGET_FREEBSD_NR_rtprio_thread: + case TARGET_FREEBSD_NR_cpuset: + case TARGET_FREEBSD_NR_cpuset_getid: + case TARGET_FREEBSD_NR_cpuset_setid: + case TARGET_FREEBSD_NR_cpuset_getaffinity: + case TARGET_FREEBSD_NR_cpuset_setaffinity: + +- case TARGET_FREEBSD_NR__umtx_lock: +- case TARGET_FREEBSD_NR__umtx_unlock: +- + case TARGET_FREEBSD_NR_rctl_get_racct: + case TARGET_FREEBSD_NR_rctl_get_rules: + case TARGET_FREEBSD_NR_rctl_add_rule: +@@ -4185,16 +4789,6 @@ do_stat: + case TARGET_FREEBSD_NR_ntp_adjtime: + case TARGET_FREEBSD_NR_ntp_gettime: + +-#ifdef TARGET_FREEBSD_NR_getdomainname +- case TARGET_FREEBSD_NR_getdomainname: +-#endif +-#ifdef TARGET_FREEBSD_NR_setdomainname +- case TARGET_FREEBSD_NR_setdomainname: +-#endif +-#ifdef TARGET_FREEBSD_NR_uname +- case TARGET_FREEBSD_NR_uname: +-#endif +- + case TARGET_FREEBSD_NR_sctp_peeloff: + case TARGET_FREEBSD_NR_sctp_generic_sendmsg: + case TARGET_FREEBSD_NR_sctp_generic_recvmsg: +diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h +index ea1d25d..2879d83 100644 +--- a/bsd-user/syscall_defs.h ++++ b/bsd-user/syscall_defs.h +@@ -416,6 +416,11 @@ struct target_shmid_ds { + abi_ulong shm_ctime; /* time of last change by shmctl() */ + }; + ++#define TARGET_UCONTEXT_MAGIC 0xACEDBADE ++#define TARGET_MC_GET_CLEAR_RET 0x0001 ++#define TARGET_MC_ADD_MAGIC 0x0002 ++#define TARGET_MC_SET_ONSTACK 0x0004 ++ + /* this struct defines a stack used during syscall handling */ + typedef struct target_sigaltstack { + abi_long ss_sp; +@@ -477,95 +482,6 @@ typedef struct target_siginfo { + } _reason; + } target_siginfo_t; + +-#if defined(TARGET_MIPS) +- +-struct target_sigcontext { +- target_sigset_t sc_mask; /* signal mask to retstore */ +- int32_t sc_onstack; /* sigstack state to restore */ +- abi_long sc_pc; /* pc at time of signal */ +- abi_long sc_reg[32]; /* processor regs 0 to 31 */ +- abi_long mullo, mulhi; /* mullo and mulhi registers */ +- int32_t sc_fpused; /* fp has been used */ +- abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ +- abi_long sc_fpc_eir; /* fp exception instr reg */ +- /* int32_t reserved[8]; */ +-}; +- +-typedef struct target_mcontext { +- int32_t mc_onstack; /* sigstack state to restore */ +- abi_long mc_pc; /* pc at time of signal */ +- abi_long mc_regs[32]; /* process regs 0 to 31 */ +- abi_long sr; /* status register */ +- abi_long mullo, mulhi; +- int32_t mc_fpused; /* fp has been used */ +- abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */ +- abi_long mc_fpc_eir; /* fp exception instr reg */ +- abi_ulong mc_tls; /* pointer to TLS area */ +-} target_mcontext_t; +- +-typedef struct target_ucontext { +- target_sigset_t uc_sigmask; +- target_mcontext_t uc_mcontext; +- target_ulong uc_link; +- target_stack_t uc_stack; +- int32_t uc_flags; +- int32_t __space__[8]; +-} target_ucontext_t; +- +-struct target_sigframe { +- abi_ulong sf_signum; +- abi_ulong sf_siginfo; /* code or pointer to sf_si */ +- abi_ulong sf_ucontext; /* points to sf_uc */ +- abi_ulong sf_addr; /* undocumented 4th arg */ +- target_ucontext_t sf_uc; /* = *sf_uncontext */ +- target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ +- uint32_t __spare__[2]; +-}; +- +-#elif defined(TARGET_SPARC64) +- +-struct target_mcontext { +- uint64_t mc_global[8]; +- uint64_t mc_out[8]; +- uint64_t mc_local[8]; +- uint64_t mc_in[8]; +- uint32_t mc_fp[64]; +-} __aligned(64); +- +-typedef struct target_mcontext target_mcontext_t; +- +-typedef struct target_ucontext { +- target_sigset_t uc_sigmask; +- target_mcontext_t uc_mcontext; +- target_ulong uc_link; +- target_stack_t uc_stack; +- int32_t uc_flags; +- int32_t __space__[8]; +-} target_ucontext_t; +- +-struct target_sigframe { +- target_ucontext_t sf_uc; +- target_siginfo_t sf_si; +-}; +- +-#else +- +-typedef target_ulong target_mcontext_t; /* dummy */ +- +-#endif +- +-/* XXX where did this come from? +-typedef struct target_ucontext { +- target_ulong uc_flags; +- target_ulong uc_link; +- target_stack_t uc_stack; +- target_mcontext_t uc_mcontext; +- target_ulong uc_filer[80]; +- target_sigset_t uc_sigmask; +-} target_ucontext_t; +-*/ +- +- + #ifdef BSWAP_NEEDED + static inline void + tswap_sigset(target_sigset_t *d, const target_sigset_t *s) +@@ -603,3 +519,101 @@ void host_to_target_old_sigset(abi_ulong *old_sigset, const sigset_t *sigset); + void target_to_host_old_sigset(sigset_t *sigset, const abi_ulong *old_sigset); + int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact); ++ ++ ++/* ++ * FreeBSD thread support. ++ */ ++ ++#define TARGET_THR_SUSPENDED 0x0001 ++#define TARGET_THR_SYSTEM_SCOPE 0x0002 ++ ++/* sysarch() ops */ ++#define TARGET_MIPS_SET_TLS 1 ++#define TARGET_MIPS_GET_TLS 2 ++ ++struct target_thr_param { ++ abi_ulong start_func; /* thread entry function. */ ++ abi_ulong arg; /* argument for entry function. */ ++ abi_ulong stack_base; /* stack base address. */ ++ abi_ulong stack_size; /* stack size. */ ++ abi_ulong tls_base; /* tls base address. */ ++ abi_ulong tls_size; /* tls size. */ ++ abi_ulong child_tid; /* address to store new TID. */ ++ abi_ulong parent_tid; /* parent access the new TID here. */ ++ abi_ulong rtp; /* Real-time scheduling priority. */ ++ abi_ulong spare[3]; /* spares. */ ++}; ++ ++struct target_rtprio { ++ uint16_t type; ++ uint16_t prio; ++}; ++ ++/* ++ * sys/_umtx.h ++ */ ++ ++struct target_umtx { ++ uint32_t u_owner; /* Owner of the mutex. */ ++}; ++ ++struct target_umutex { ++ uint32_t m_owner; /* Owner of the mutex */ ++ uint32_t m_flags; /* Flags of the mutex */ ++ uint32_t m_ceiling[2]; /* Priority protect ceiling */ ++ uint32_t m_spare[4]; ++}; ++ ++struct target_ucond { ++ uint32_t c_has_waiters; /* Has waiters in kernel */ ++ uint32_t c_flags; /* Flags of the condition variable */ ++ uint32_t c_clockid; /* Clock id */ ++ uint32_t c_spare[1]; ++}; ++ ++struct target_urwlock { ++ int32_t rw_state; ++ uint32_t rw_flags; ++ uint32_t rw_blocked_readers; ++ uint32_t rw_blocked_writers; ++ uint32_t rw_spare[4]; ++}; ++ ++struct target__usem { ++ uint32_t _has_waiters; ++ uint32_t _count; ++ uint32_t _flags; ++}; ++ ++/* ++ * sys/utmx.h ++ */ ++ ++/* op code for _umtx_op */ ++#define TARGET_UMTX_OP_LOCK 0 ++#define TARGET_UMTX_OP_UNLOCK 1 ++#define TARGET_UMTX_OP_WAIT 2 ++#define TARGET_UMTX_OP_WAKE 3 ++#define TARGET_UMTX_OP_MUTEX_TRYLOCK 4 ++#define TARGET_UMTX_OP_MUTEX_LOCK 5 ++#define TARGET_UMTX_OP_MUTEX_UNLOCK 6 ++#define TARGET_UMTX_OP_SET_CEILING 7 ++#define TARGET_UMTX_OP_CV_WAIT 8 ++#define TARGET_UMTX_OP_CV_SIGNAL 9 ++#define TARGET_UMTX_OP_CV_BROADCAST 10 ++#define TARGET_UMTX_OP_WAIT_UINT 11 ++#define TARGET_UMTX_OP_RW_RDLOCK 12 ++#define TARGET_UMTX_OP_RW_WRLOCK 13 ++#define TARGET_UMTX_OP_RW_UNLOCK 14 ++#define TARGET_UMTX_OP_WAIT_UINT_PRIVATE 15 ++#define TARGET_UMTX_OP_WAKE_PRIVATE 16 ++#define TARGET_UMTX_OP_MUTEX_WAIT 17 ++#define TARGET_UMTX_OP_MUTEX_WAKE 18 ++#define TARGET_UMTX_OP_SEM_WAIT 19 ++#define TARGET_UMTX_OP_SEM_WAKE 20 ++#define TARGET_UMTX_OP_NWAKE_PRIVATE 21 ++#define TARGET_UMTX_OP_MAX 22 ++ ++/* flags for UMTX_OP_CV_WAIT */ ++#define TARGET_CHECK_UNPARKING 0x01 +diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h +index ea89f5a..a14e0b9 100644 +--- a/bsd-user/x86_64/target_signal.h ++++ b/bsd-user/x86_64/target_signal.h +@@ -15,4 +15,29 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) + #define TARGET_MINSIGSTKSZ (512 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + ++typedef target_ulong target_mcontext_t; /* dummy */ ++ ++typedef struct target_ucontext { ++ target_sigset_t uc_sigmask; ++ target_mcontext_t uc_mcontext; ++ abi_ulong uc_link; ++ target_stack_t uc_stack; ++ int32_t uc_flags; ++ int32_t __spare__[4]; ++} target_ucontext_t; ++ ++static inline int ++get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "x86_64 doesn't have support for get_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ ++static inline int ++set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++{ ++ fprintf(stderr, "x86_64 doesn't have support for set_mcontext()\n"); ++ return (-TARGET_ENOSYS); ++} ++ + #endif /* TARGET_SIGNAL_H */ +diff --git a/configure b/configure +index 34eca43..be75584 100755 +--- a/configure ++++ b/configure +@@ -1386,6 +1386,11 @@ fi + + if test "$nptl" != "no" ; then + cat > $TMPC < + #include + int main(void) { +@@ -1394,6 +1399,7 @@ int main(void) { + #endif + return 0; + } ++#endif + EOF + + if compile_object ; then +@@ -3751,5 +3757,6 @@ case "$target_arch2" in + TARGET_ARCH=mips64 + TARGET_BASE_ARCH=mips + echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak ++ target_nptl="yes" + target_long_alignment=8 + ;; Index: files/patch-z2d-bsd-user-sson-002d @@ -0,0 +1,30 @@ +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index 4deb0db..bde9ee9 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -2377,7 +2377,7 @@ do_thr_exit(CPUArchState *cpu_env, abi_ulong tid_addr) + + if (tid_addr) { + /* Signal target userland that it can free the stack. */ +- if (! put_user_u32(1, tid_addr)) ++ if (! put_user_sal(1, tid_addr)) + _umtx_op(g2h(tid_addr), UMTX_OP_WAKE, INT_MAX, + NULL, NULL); + } +@@ -4588,10 +4588,13 @@ do_stat: + { + struct timespec ts; + +- if (target_to_host_timespec(&ts, arg1)) +- goto efault; ++ if (arg1) { ++ if (target_to_host_timespec(&ts, arg1)) ++ goto efault; ++ ret = do_thr_suspend(&ts); ++ } else ++ ret = do_thr_suspend(NULL); + +- ret = do_thr_suspend(&ts); + } + break; + Index: files/patch-z2e-bsd-user-sson-002e @@ -0,0 +1,3316 @@ +diff --git a/Makefile.target b/Makefile.target +--- a/Makefile.target ++++ b/Makefile.target +@@ -95,7 +95,7 @@ ifdef CONFIG_BSD_USER + QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) + + obj-y += bsd-user/ +-obj-y += gdbstub.o user-exec.o ++obj-y += gdbstub.o thunk.o user-exec.o + + endif #CONFIG_BSD_USER + +diff --git a/bsd-user/freebsd/ioccom.h b/bsd-user/freebsd/ioccom.h +new file mode 100644 +index 0000000..830e377 +--- /dev/null ++++ b/bsd-user/freebsd/ioccom.h +@@ -0,0 +1,34 @@ ++#ifndef _FREEBSD_IOCCOM_H_ ++#define _FREEBSD_IOCCOM_H_ ++/* ++ * Ioctl's have the command encoded in the lower word, and the size of ++ * any in or out parameters in the upper word. The high 3 bits of the ++ * upper word are used to encode the in/out status of the parameter. ++ */ ++/* number of bits for ioctl size */ ++#define TARGET_IOCPARM_SHIFT 13 ++ ++/* parameter length mask */ ++#define TARGET_IOCPARM_MASK ((1 << TARGET_IOCPARM_SHIFT) - 1) ++ ++#define TARGET_IOCPARM_LEN(x) (((x) >> 16) & TARGET_IOCPARM_MASK) ++#define TARGET_IOCBASECMD(x) ((x) & ~(TARGET_IOCPARM_MASK << 16)) ++#define TARGET_IOCGROUP(x) (((x) >> 8) & 0xff) ++ ++#define TARGET_IOCPARM_MAX (1 << TARGET_IOCPARM_SHIFT) /* max size of ioctl */ ++#define TARGET_IOC_VOID 0x20000000 /* no parameters */ ++#define TARGET_IOC_OUT 0x40000000 /* copy out parameters */ ++#define TARGET_IOC_IN 0x80000000 /* copy in parameters */ ++#define TARGET_IOC_INOUT (TARGET_IOC_IN|TARGET_IOC_OUT) ++#define TARGET_IOC_DIRMASK (TARGET_IOC_VOID|TARGET_IOC_OUT|TARGET_IOC_IN) ++ ++#define TARGET_IOC(inout,group,num,len) ((abi_ulong) \ ++ ((inout) | (((len) & TARGET_IOCPARM_MASK) << 16) | ((group) << 8) \ ++ | (num))) ++#define TARGET_IO(g,n) TARGET_IOC(IOC_VOID, (g), (n), 0) ++#define TARGET_IOWINT(g,n) TARGET_IOC(IOC_VOID, (g), (n), sizeof(int)) ++#define TARGET_IOR(g,n,t) TARGET_IOC(IOC_OUT, (g), (n), sizeof(t)) ++#define TARGET_IOW(g,n,t) TARGET_IOC(IOC_IN, (g), (n), sizeof(t)) ++/* this should be _IORW, but stdio got there first */ ++#define TARGET_IOWR(g,n,t) TARGET_IOC(IOC_INOUT, (g), (n), sizeof(t)) ++#endif +diff --git a/bsd-user/freebsd/ioctl.h b/bsd-user/freebsd/ioctl.h +new file mode 100644 +index 0000000..67c5583 +--- /dev/null ++++ b/bsd-user/freebsd/ioctl.h +@@ -0,0 +1,35 @@ ++#ifndef _FREEBSD_IOCTL_H_ ++#define _FREEBSD_IOCTL_H_ ++ ++/* sys/ttycom.h tty(4) */ ++IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(TIOCSBRK, IOC_, TYPE_NULL) ++IOCTL(TIOCCBRK, IOC_, TYPE_NULL) ++IOCTL(TIOCSDTR, IOC_, TYPE_NULL) ++IOCTL(TIOCCDTR, IOC_, TYPE_NULL) ++IOCTL(TIOCGPGRP, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(TIOCSPGRP, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) ++IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) ++IOCTL(TIOCSETAW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) ++IOCTL(TIOCSETAF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) ++IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_CHAR)) ++IOCTL(TIOCNOTTY, IOC_, TYPE_NULL) ++IOCTL(TIOCSTOP, IOC_, TYPE_NULL) ++IOCTL(TIOCSTART, IOC_, TYPE_NULL) ++IOCTL(TIOCSCTTY, IOC_, TYPE_NULL) ++IOCTL(TIOCDRAIN, IOC_, TYPE_NULL) ++IOCTL(TIOCEXCL, IOC_, TYPE_NULL) ++IOCTL(TIOCNXCL, IOC_, TYPE_NULL) ++IOCTL(TIOCFLUSH, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize))) ++IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize))) ++IOCTL(TIOCCONS, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT)) ++ ++#endif +diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list +index b09f766..bcdd931 100644 +--- a/bsd-user/freebsd/strace.list ++++ b/bsd-user/freebsd/strace.list +@@ -2,6 +2,7 @@ + { TARGET_FREEBSD_NR___semctl, "__semctl", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR___syscall, "__syscall", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR___sysctl, "__sysctl", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR__umtx_op, "_umtx_op", "%s(%#x, %d, %d, %#x, %#x)", NULL, NULL }, + { TARGET_FREEBSD_NR_accept, "accept", "%s(%d,%#x,%#x)", NULL, NULL }, + { TARGET_FREEBSD_NR_access, "access", "%s(\"%s\",%#o)", NULL, NULL }, + { TARGET_FREEBSD_NR_acct, "acct", NULL, NULL, NULL }, +diff --git a/bsd-user/freebsd/syscall_types.h b/bsd-user/freebsd/syscall_types.h +new file mode 100644 +index 0000000..6e43400 +--- /dev/null ++++ b/bsd-user/freebsd/syscall_types.h +@@ -0,0 +1,8 @@ ++#ifndef _FREEBSD_SYSCALL_TYPES_H_ ++#define _FREEBSD_SYSCALL_TYPES_H_ ++ ++STRUCT_SPECIAL(termios) ++ ++STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT) ++ ++#endif +diff --git a/bsd-user/freebsd/ttycom.h b/bsd-user/freebsd/ttycom.h +new file mode 100644 +index 0000000..699c282 +--- /dev/null ++++ b/bsd-user/freebsd/ttycom.h +@@ -0,0 +1,238 @@ ++#ifndef _FREEBSD_TTYCOM_H_ ++#define _FREEBSD_TTYCOM_H_ ++ ++#include "ioccom.h" ++ ++/* From sys/ttycom.h and sys/_termios.h */ ++ ++#define TARGET_VEOF 0 /* ICANON */ ++#define TARGET_VEOL 1 /* ICANON */ ++#define TARGET_VEOL2 2 /* ICANON together with IEXTEN */ ++#define TARGET_VERASE 3 /* ICANON */ ++#define TARGET_VWERASE 4 /* ICANON together with IEXTEN */ ++#define TARGET_VKILL 5 /* ICANON */ ++#define TARGET_VREPRINT 6 /* ICANON together with IEXTEN */ ++#define TARGET_VERASE2 7 /* ICANON */ ++#define TARGET_VINTR 8 /* ISIG */ ++#define TARGET_VQUIT 9 /* ISIG */ ++#define TARGET_VSUSP 10 /* ISIG */ ++#define TARGET_VDSUSP 11 /* ISIG together with IEXTEN */ ++#define TARGET_VSTART 12 /* IXON, IXOFF */ ++#define TARGET_VSTOP 13 /* IXON, IXOFF */ ++#define TARGET_VLNEXT 14 /* IEXTEN */ ++#define TARGET_VDISCARD 15 /* IEXTEN */ ++#define TARGET_VMIN 16 /* !ICANON */ ++#define TARGET_VTIME 17 /* !ICANON */ ++#define TARGET_VSTATUS 18 /* ICANON together with IEXTEN */ ++/* 19 spare 2 */ ++#define TARGET_NCCS 20 ++ ++/* ++ * Input flags - software input processing ++ */ ++#define TARGET_IGNBRK 0x00000001 /* ignore BREAK condition */ ++#define TARGET_BRKINT 0x00000002 /* map BREAK to SIGINTR */ ++#define TARGET_IGNPAR 0x00000004 /* ignore (discard) parity errors */ ++#define TARGET_PARMRK 0x00000008 /* mark parity and framing errors */ ++#define TARGET_INPCK 0x00000010 /* enable checking of parity errors */ ++#define TARGET_ISTRIP 0x00000020 /* strip 8th bit off chars */ ++#define TARGET_INLCR 0x00000040 /* map NL into CR */ ++#define TARGET_IGNCR 0x00000080 /* ignore CR */ ++#define TARGET_ICRNL 0x00000100 /* map CR to NL (ala CRMOD) */ ++#define TARGET_IXON 0x00000200 /* enable output flow control */ ++#define TARGET_IXOFF 0x00000400 /* enable input flow control */ ++#define TARGET_IXANY 0x00000800 /* any char will restart after stop */ ++#define TARGET_IMAXBEL 0x00002000 /* ring bell on input queue full */ ++ ++/* ++ * Output flags - software output processing ++ */ ++#define TARGET_OPOST 0x00000001 /* enable following output processing */ ++#define TARGET_ONLCR 0x00000002 /* map NL to CR-NL (ala CRMOD) */ ++#define TARGET_TABDLY 0x00000004 /* tab delay mask */ ++#define TARGET_TAB0 0x00000000 /* no tab delay and expansion */ ++#define TARGET_TAB3 0x00000004 /* expand tabs to spaces */ ++#define TARGET_ONOEOT 0x00000008 /* discard EOT's (^D) on output) */ ++#define TARGET_OCRNL 0x00000010 /* map CR to NL on output */ ++#define TARGET_ONOCR 0x00000020 /* no CR output at column 0 */ ++#define TARGET_ONLRET 0x00000040 /* NL performs CR function */ ++ ++/* ++ * Control flags - hardware control of terminal ++ */ ++#define TARGET_CIGNORE 0x00000001 /* ignore control flags */ ++#define TARGET_CSIZE 0x00000300 /* character size mask */ ++#define TARGET_CS5 0x00000000 /* 5 bits (pseudo) */ ++#define TARGET_CS6 0x00000100 /* 6 bits */ ++#define TARGET_CS7 0x00000200 /* 7 bits */ ++#define TARGET_CS8 0x00000300 /* 8 bits */ ++#define TARGET_CSTOPB 0x00000400 /* send 2 stop bits */ ++#define TARGET_CREAD 0x00000800 /* enable receiver */ ++#define TARGET_PARENB 0x00001000 /* parity enable */ ++#define TARGET_PARODD 0x00002000 /* odd parity, else even */ ++#define TARGET_HUPCL 0x00004000 /* hang up on last close */ ++#define TARGET_CLOCAL 0x00008000 /* ignore modem status lines */ ++#define TARGET_CCTS_OFLOW 0x00010000 /* CTS flow control of output */ ++#define TARGET_CRTSCTS (TARGET_CCTS_OFLOW | TARGET_CRTS_IFLOW) ++#define TARGET_CRTS_IFLOW 0x00020000 /* RTS flow control of input */ ++#define TARGET_CDTR_IFLOW 0x00040000 /* DTR flow control of input */ ++#define TARGET_CDSR_OFLOW 0x00080000 /* DSR flow control of output */ ++#define TARGET_CCAR_OFLOW 0x00100000 /* DCD flow control of output */ ++ ++/* ++ * "Local" flags - dumping ground for other state ++ */ ++#define TARGET_ECHOKE 0x00000001 /* visual erase for line kill */ ++#define TARGET_ECHOE 0x00000002 /* visually erase chars */ ++#define TARGET_ECHOK 0x00000004 /* echo NL after line kill */ ++#define TARGET_ECHO 0x00000008 /* enable echoing */ ++#define TARGET_ECHONL 0x00000010 /* echo NL even if ECHO is off */ ++#define TARGET_ECHOPRT 0x00000020 /* visual erase mode for hardcopy */ ++#define TARGET_ECHOCTL 0x00000040 /* echo control chars as ^(Char) */ ++#define TARGET_ISIG 0x00000080 /* enable signals INTR, QUIT, [D]SUSP */ ++#define TARGET_ICANON 0x00000100 /* canonicalize input lines */ ++#define TARGET_ALTWERASE 0x00000200 /* use alternate WERASE algorithm */ ++#define TARGET_IEXTEN 0x00000400 /* enable DISCARD and LNEXT */ ++#define TARGET_EXTPROC 0x00000800 /* external processing */ ++#define TARGET_TOSTOP 0x00400000 /* stop background jobs from output */ ++#define TARGET_FLUSHO 0x00800000 /* output being flushed (state) */ ++#define TARGET_NOKERNINFO 0x02000000 /* no kernel output from VSTATUS */ ++#define TARGET_PENDIN 0x20000000 /* XXX retype pending input (state) */ ++#define TARGET_NOFLSH 0x80000000 /* don't flush after interrupt */ ++ ++struct target_termios { ++ uint32_t c_iflag; /* input flags */ ++ uint32_t c_oflag; /* output flags */ ++ uint32_t c_cflag; /* control flags */ ++ uint32_t c_lflag; /* local flags */ ++ uint8_t c_cc[TARGET_NCCS]; /* control chars */ ++ uint32_t c_ispeed; /* input speed */ ++ uint32_t c_ospeed; /* output speed */ ++}; ++ ++ ++struct target_winsize { ++ uint16_t ws_row; /* rows, in characters */ ++ uint16_t ws_col; /* columns, in characters */ ++ uint16_t ws_xpixel; /* horizontal size, pixels */ ++ uint16_t ws_ypixel; /* vertical size, pixels */ ++}; ++ ++ /* 0-2 compat */ ++ /* 3-7 unused */ ++ /* 8-10 compat */ ++ /* 11-12 unused */ ++#define TARGET_TIOCEXCL TARGET_IO('t', 13) /* set exclusive use of tty */ ++#define TARGET_TIOCNXCL TARGET_IO('t', 14) /* reset exclusive use of tty */ ++#define TARGET_TIOCGPTN TARGET_IOR('t', 15, int) /* Get pts number. */ ++#define TARGET_TIOCFLUSH TARGET_IOW('t', 16, int) /* flush buffers */ ++ /* 17-18 compat */ ++/* get termios struct */ ++#define TARGET_TIOCGETA TARGET_IOR('t', 19, struct target_termios) ++/* set termios struct */ ++#define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios) ++/* drain output, set */ ++#define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct target_termios) ++/* drn out, fls in, set */ ++#define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct target_termios) ++ /* 23-25 unused */ ++#define TARGET_TIOCGETD TARGET_IOR('t', 26, int) /* get line discipline */ ++#define TARGET_TIOCSETD TARGET_IOW('t', 27, int) /* set line discipline */ ++#define TARGET_TIOCPTMASTER TARGET_IO('t', 28) /* pts master validation */ ++ /* 29-85 unused */ ++/* get ttywait timeout */ ++#define TARGET_TIOCGDRAINWAIT TARGET_IOR('t', 86, int) ++/* set ttywait timeout */ ++#define TARGET_TIOCSDRAINWAIT TARGET_IOW('t', 87, int) ++ /* 88 unused */ ++ /* 89-91 conflicts: tun and tap */ ++/* enable/get timestamp of last input event */ ++#define TARGET_TIOCTIMESTAMP TARGET_IOR('t', 89, struct target_timeval) ++/* modem: get wait on close */ ++#define TARGET_TIOCMGDTRWAIT TARGET_IOR('t', 90, int) ++/* modem: set wait on close */ ++#define TARGET_TIOCMSDTRWAIT TARGET_IOW('t', 91, int) ++ /* 92-93 tun and tap */ ++ /* 94-97 conflicts: tun and tap */ ++/* wait till output drained */ ++#define TARGET_TIOCDRAIN TARGET_IO('t', 94) ++ /* pty: generate signal */ ++#define TARGET_TIOCSIG TARGET_IOWINT('t', 95) ++/* pty: external processing */ ++#define TARGET_TIOCEXT TARGET_IOW('t', 96, int) ++/* become controlling tty */ ++#define TARGET_TIOCSCTTY TARGET_IO('t', 97) ++/* become virtual console */ ++#define TARGET_TIOCCONS TARGET_IOW('t', 98, int) ++/* get session id */ ++#define TARGET_TIOCGSID TARGET_IOR('t', 99, int) ++ /* 100 unused */ ++/* simulate ^T status message */ ++#define TARGET_TIOCSTAT TARGET_IO('t', 101) ++ /* pty: set/clr usr cntl mode */ ++#define TARGET_TIOCUCNTL TARGET_IOW('t', 102, int) ++/* usr cntl op "n" */ ++#define TARGET_TIOCCMD(n) TARGET_IO('u', n) ++/* set window size */ ++#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) ++/* get window size */ ++#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) ++ /* 105 unused */ ++/* get all modem bits */ ++#define TARGET_TIOCMGET TARGET_IOR('t', 106, int) ++#define TARGET_TIOCM_LE 0001 /* line enable */ ++#define TARGET_TIOCM_DTR 0002 /* data terminal ready */ ++#define TARGET_TIOCM_RTS 0004 /* request to send */ ++#define TARGET_TIOCM_ST 0010 /* secondary transmit */ ++#define TARGET_TIOCM_SR 0020 /* secondary receive */ ++#define TARGET_TIOCM_CTS 0040 /* clear to send */ ++#define TARGET_TIOCM_DCD 0100 /* data carrier detect */ ++#define TARGET_TIOCM_RI 0200 /* ring indicate */ ++#define TARGET_TIOCM_DSR 0400 /* data set ready */ ++#define TARGET_TIOCM_CD TARGET_TIOCM_DCD ++#define TARGET_TIOCM_CAR TARGET_TIOCM_DCD ++#define TARGET_TIOCM_RNG TARGET_TIOCM_RI ++#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) /* bic modem bits */ ++#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) /* bis modem bits */ ++#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) /* set all modem bits */ ++/* start output, like ^Q */ ++#define TARGET_TIOCSTART TARGET_IO('t', 110) ++/* stop output, like ^S */ ++#define TARGET_TIOCSTOP TARGET_IO('t', 111) ++/* pty: set/clear packet mode */ ++#define TARGET_TIOCPKT TARGET_IOW('t', 112, int) ++#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ ++#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ ++#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ ++#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ ++#define TARGET_TIOCPKT_START 0x08 /* start output */ ++#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ ++#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ ++#define TARGET_TIOCPKT_IOCTL 0x40 /* state change of pty ++ driver */ ++#define TARGET_TIOCNOTTY TARGET_IO('t', 113) /* void tty ++ association */ ++#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) /* simulate ++ terminal input */ ++#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ ++ /* 116-117 compat */ ++#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ ++#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ ++#define TARGET_TIOCCDTR TARGET_IO('t', 120) /* clear data terminal ++ ready */ ++#define TARGET_TIOCSDTR TARGET_IO('t', 121) /* set data terminal ++ ready */ ++#define TARGET_TIOCCBRK TARGET_IO('t', 122) /* clear break bit */ ++#define TARGET_TIOCSBRK TARGET_IO('t', 123) /* set break bit */ ++ /* 124-127 compat */ ++ ++#define TARGET_TTYDISC 0 /* termios tty line ++ discipline */ ++#define TARGET_SLIPDISC 4 /* serial IP discipline */ ++#define TARGET_PPPDISC 5 /* PPP discipline */ ++#define TARGET_NETGRAPHDISC 6 /* Netgraph tty node ++ discipline */ ++#define TARGET_H4DISC 7 /* Netgraph Bluetooth H4 ++ discipline */ ++ ++#endif /* _FREEBSD_TTYCOM_H_ */ +diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h +index 9d4edbf..e3bcc57 100644 +--- a/bsd-user/qemu.h ++++ b/bsd-user/qemu.h +@@ -23,6 +23,7 @@ extern enum BSDType bsd_type; + abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len); + ++#include "exec/user/thunk.h" + #include "syscall_defs.h" + #include "syscall.h" + #include "target_vmparam.h" +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index bde9ee9..89ce296 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -47,6 +47,12 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include + #include + #include + #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_. */ +-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_. */ ++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; ++}; Index: files/patch-z3-bsd-user-8fix @@ -0,0 +1,61 @@ +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -17,6 +17,18 @@ + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ ++ ++#if defined(__FreeBSD__) ++#include ++#endif ++ ++#if defined(__FreeBSD_version) && __FreeBSD_version < 900000 ++#define st_atim st_atimespec ++#define st_ctim st_ctimespec ++#define st_mtim st_mtimespec ++#define st_birthtim st_birthtimespec ++#endif ++ + #include + #include + #include +@@ -1519,9 +1533,11 @@ do_setsockopt(int sockfd, int level, int + optname = SO_ERROR; + break; + ++#ifdef SO_USER_COOKIE + case TARGET_SO_USER_COOKIE: + optname = SO_USER_COOKIE; + break; ++#endif + + default: + goto unimplemented; +@@ -2091,9 +2107,11 @@ do_fork(CPUArchState *env, int num, int + ret = rfork(flags); + break; + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case TARGET_FREEBSD_NR_pdfork: + ret = pdfork(&fd, flags); + break; ++#endif + + default: + ret = -TARGET_ENOSYS; +@@ -3499,6 +3517,7 @@ do_stat: + unlock_user(p, arg1, 0); + break; + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case TARGET_FREEBSD_NR_setloginclass: + if (!(p = lock_user_string(arg1))) + goto efault; +@@ -3512,6 +3531,7 @@ do_stat: + ret = get_errno(getloginclass(p, arg2)); + unlock_user(p, arg1, 0); + break; ++#endif + + case TARGET_FREEBSD_NR_getrusage: + { Index: files/patch-z3b-bsd-user-8fix @@ -0,0 +1,34 @@ +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -3890,6 +3890,7 @@ do_stat: + break; + #endif + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case TARGET_FREEBSD_NR_pdkill: + ret = get_errno(pdkill(arg1, target_to_host_signal(arg2))); + break; +@@ -3903,6 +3904,7 @@ do_stat: + goto efault; + } + break; ++#endif + + case TARGET_FREEBSD_NR_sigaction: + { +@@ -4176,6 +4178,7 @@ do_stat: + break; + #endif + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case TARGET_FREEBSD_NR_posix_fallocate: + { + off_t offset = arg2, len = arg3; +@@ -4192,6 +4195,7 @@ do_stat: + ret = get_errno(posix_fallocate(arg1, offset, len)); + } + break; ++#endif + + #ifdef TARGET_FREEBSD_posix_openpt + case TARGET_FREEBSD_posix_openpt: Index: files/patch-z3c-bsd-user-8fix @@ -0,0 +1,12 @@ +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -54,7 +54,9 @@ + #include + #ifdef __FreeBSD__ + #include ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + #include ++#endif + #include + #include + #include --- /dev/null 2013-03-19 20:23:25.000000000 +0100 +++ files/patch-z3d-bsd-user-8fix 2013-02-17 19:41:31.000000000 +0100 @@ -0,0 +1,47 @@ +--- qemu-1.4.0/bsd-user/syscall.c.orig ++++ qemu-1.4.0/bsd-user/syscall.c +@@ -62,7 +62,11 @@ + #include + #include + #include ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + #include ++#else ++#include ++#endif + #include + #include + #include +@@ -6383,6 +6387,7 @@ abi_long do_freebsd_syscall(void *cpu_en + val, NULL, NULL)); + break; + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case TARGET_UMTX_OP_NWAKE_PRIVATE: + if (! access_ok(VERIFY_READ, obj, + val * sizeof(uint32_t))) +@@ -6390,7 +6395,7 @@ abi_long do_freebsd_syscall(void *cpu_en + ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_NWAKE_PRIVATE, + val, NULL, NULL)); + break; +- ++#endif + + case TARGET_UMTX_OP_RW_RDLOCK: + if (target_ts) { +@@ -6425,6 +6430,7 @@ abi_long do_freebsd_syscall(void *cpu_en + break; + #endif + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case TARGET_UMTX_OP_SEM_WAIT: + /* XXX Assumes struct _usem is opauque to the user */ + if (! access_ok(VERIFY_WRITE, obj, +@@ -6447,6 +6453,7 @@ abi_long do_freebsd_syscall(void *cpu_en + ret = get_errno(_umtx_op(g2h(obj), UMTX_OP_SEM_WAKE, + val, NULL, NULL)); + break; ++#endif + + default: + ret = -TARGET_EINVAL; Index: files/patch-z4-bsd-user-elfload @@ -0,0 +1,26 @@ +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -812,8 +812,9 @@ static abi_ulong setup_arg_pages(abi_ulo + * Add argv strings. Note that the argv[] vectors are added by + * loader_build_argptr() + */ +- i = bprm->argc; +- while (i-- > 0) { ++ // i = bprm->argc; ++ // while (i-- > 0) { ++ for (i = 0; i < bprm->argc; ++i) { + size_t len = strlen(bprm->argv[i]) + 1; + /* XXX - check return value of memcpy_to_target(). */ + memcpy_to_target(destp, bprm->argv[i], len); +@@ -826,8 +827,9 @@ static abi_ulong setup_arg_pages(abi_ulo + * Add env strings. Note that the envp[] vectors are added by + * loader_build_argptr(). + */ +- i = bprm->envc; +- while(i-- > 0) { ++ // i = bprm->envc; ++ // while(i-- > 0) { ++ for (i = 0; i < bprm->envc; ++i) { + size_t len = strlen(bprm->envp[i]) + 1; + /* XXX - check return value of memcpy_to_target(). */ + memcpy_to_target(destp, bprm->envp[i], len); Index: files/patch-z6-bsd-user-usrstack1 @@ -0,0 +1,18 @@ +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -377,6 +377,15 @@ static abi_long do_freebsd_sysctl(abi_ul + *q++ = tswap32(*p); + oidfmt(snamep, namelen, NULL, &kind); + /* XXX swap hnewp */ ++#if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 ++ /* XXX there may be more sysctls that differ */ ++ if (namelen == 2 && ++ snamep[0] == CTL_KERN && snamep[1] == KERN_USRSTACK && ++ holdlen && holdlen == 4 && hnewp == NULL) { ++ (*(uint32_t *)holdp) = 0xfffff000U; ++ ret = 0; ++ } else ++#endif + ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); + if (!ret) + sysctl_oldcvt(holdp, holdlen, kind); Index: files/patch-z7-bsd-user-tls1-cognet @@ -0,0 +1,171 @@ +--- oldqemu-1.3.0/bsd-user/syscall.c 2012-12-13 23:51:09.000000000 +0100 ++++ qemu-1.3.0/bsd-user/syscall.c 2012-12-13 23:46:55.000000000 +0100 +@@ -258,6 +258,16 @@ static abi_long do_freebsd_sysarch(void + #ifdef TARGET_ARM + static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + { ++ abi_ulong val; ++ ++ switch (op) { ++ case TARGET_FREEBSD_ARM_SET_TP: ++ if (get_user(val, parms, abi_ulong)) ++ return -TARGET_EINVAL; ++ cpu_set_tls(env, val); ++ return 0; ++ } ++ + return -TARGET_EINVAL; + } + #endif +--- oldqemu-1.3.0/bsd-user/elfload.c 2012-12-13 23:51:09.000000000 +0100 ++++ qemu-1.3.0/bsd-user/elfload.c 2012-12-13 23:50:14.000000000 +0100 +@@ -948,10 +948,8 @@ static abi_ulong create_elf_tables(abi_u + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (abi_ulong)15; +-#ifdef __FreeBSD__ +- size = 0; +-#else + size = (DLINFO_ITEMS + 1) * 2; ++#ifndef __FreeBSD__ + if (k_platform) + size += 2; + #ifdef DLINFO_ARCH_ITEMS +@@ -964,7 +962,6 @@ static abi_ulong create_elf_tables(abi_u + if (size & 15) + sp -= 16 - (size & 15); + +-#ifndef __FreeBSD__ + /* This is correct because Linux defines + * elf_addr_t as Elf32_Off / Elf64_Off + */ +@@ -989,8 +986,10 @@ static abi_ulong create_elf_tables(abi_u + NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); ++#ifndef __FreeBSD__ + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, u_platform); ++#endif + #ifdef ARCH_DLINFO + /* + * ARCH_DLINFO must come last so platform specific code can enforce +@@ -999,7 +998,6 @@ static abi_ulong create_elf_tables(abi_u + ARCH_DLINFO; + #endif + #undef NEW_AUX_ENT +-#endif /* ! __FreeBSD__ */ + + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); + return sp; +--- oldqemu-1.3.0/bsd-user/main.c 2012-12-13 23:51:09.000000000 +0100 ++++ qemu-1.3.0/bsd-user/main.c 2012-12-13 23:01:30.000000000 +0100 +@@ -392,6 +392,84 @@ void cpu_loop(CPUX86State *env) + #ifdef TARGET_ARM + // #define DEBUG_ARM + ++static int do_strex(CPUARMState *env) ++{ ++ uint32_t val; ++ int size; ++ int rc = 1; ++ int segv = 0; ++ uint32_t addr; ++ start_exclusive(); ++ addr = env->exclusive_addr; ++ if (addr != env->exclusive_test) { ++ goto fail; ++ } ++ size = env->exclusive_info & 0xf; ++ switch (size) { ++ case 0: ++ segv = get_user_u8(val, addr); ++ break; ++ case 1: ++ segv = get_user_u16(val, addr); ++ break; ++ case 2: ++ case 3: ++ segv = get_user_u32(val, addr); ++ break; ++ default: ++ abort(); ++ } ++ if (segv) { ++ env->cp15.c6_data = addr; ++ goto done; ++ } ++ if (val != env->exclusive_val) { ++ goto fail; ++ } ++ if (size == 3) { ++ segv = get_user_u32(val, addr + 4); ++ if (segv) { ++ env->cp15.c6_data = addr + 4; ++ goto done; ++ } ++ if (val != env->exclusive_high) { ++ goto fail; ++ } ++ } ++ val = env->regs[(env->exclusive_info >> 8) & 0xf]; ++ switch (size) { ++ case 0: ++ segv = put_user_u8(val, addr); ++ break; ++ case 1: ++ segv = put_user_u16(val, addr); ++ break; ++ case 2: ++ case 3: ++ segv = put_user_u32(val, addr); ++ break; ++ } ++ if (segv) { ++ env->cp15.c6_data = addr; ++ goto done; ++ } ++ if (size == 3) { ++ val = env->regs[(env->exclusive_info >> 12) & 0xf]; ++ segv = put_user_u32(val, addr + 4); ++ if (segv) { ++ env->cp15.c6_data = addr + 4; ++ goto done; ++ } ++ } ++ rc = 0; ++fail: ++ env->regs[15] += 4; ++ env->regs[(env->exclusive_info >> 4) & 0xf] = rc; ++done: ++ end_exclusive(); ++ return segv; ++} ++ + void cpu_loop(CPUARMState *env) + { + int trapnr; +@@ -622,6 +700,7 @@ void cpu_loop(CPUARMState *env) + if (do_kernel_trap(env)) + goto error; + break; ++#endif + case EXCP_STREX: + if (do_strex(env)) { + addr = env->cp15.c6_data; +@@ -629,7 +708,6 @@ void cpu_loop(CPUARMState *env) + } + break; + error: +-#endif + default: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); +--- oldqemu-1.3.0/bsd-user/arm/syscall.h 2012-12-13 23:51:09.000000000 +0100 ++++ qemu-1.3.0/bsd-user/arm/syscall.h 2012-12-13 23:45:22.000000000 +0100 +@@ -21,3 +21,5 @@ struct target_pt_regs { + #define ARM_r0 uregs[0] + + #define ARM_SYSCALL_BASE 0 /* XXX: FreeBSD only */ ++ ++#define TARGET_FREEBSD_ARM_SET_TP 2 Index: files/patch-z7b-bsd-user-tls2 @@ -0,0 +1,13 @@ +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -266,9 +268,7 @@ static abi_long do_freebsd_sysarch(void + + switch (op) { + case TARGET_FREEBSD_ARM_SET_TP: +- if (get_user(val, parms, abi_ulong)) +- return -TARGET_EINVAL; +- cpu_set_tls(env, val); ++ cpu_set_tls(env, parms); + return 0; + } + Index: files/patch-z8-bsd-user-unref @@ -0,0 +1,11 @@ +--- qemu-1.4.0/bsd-user/syscall.c.orig ++++ qemu-1.4.0/bsd-user/syscall.c +@@ -2418,7 +2418,7 @@ do_thr_exit(CPUArchState *cpu_env, abi_u + } + + thread_env = NULL; +- object_delete(OBJECT(ENV_GET_CPU(cpu_env))); ++ object_unref(OBJECT(ENV_GET_CPU(cpu_env))); + g_free(ts); + pthread_exit(NULL); + } Index: files/patch-z9-bsd-user-sson003a @@ -0,0 +1,40 @@ +diff --git a/bsd-user/freebsd/ioctl.h b/bsd-user/freebsd/ioctl.h +index 67c5583..f83f6c1 100644 +--- a/bsd-user/freebsd/ioctl.h ++++ b/bsd-user/freebsd/ioctl.h +@@ -8,8 +8,8 @@ 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(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(TIOCSPGRP, IOC_W, 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))) +diff --git a/bsd-user/main.c b/bsd-user/main.c +index d9a0ecd..7cc77aa 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -1907,7 +1907,7 @@ int main(int argc, char **argv) + env->hflags |= MIPS_HFLAG_M16; + } + #if defined(TARGET_MIPS64) +- env->hflags |= MIPS_HFLAG_UX; ++ env->hflags |= MIPS_HFLAG_UX | MIPS_HFLAG_64; + #endif + } + #else +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index 581a31f..a40d7ce 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -278,7 +278,6 @@ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + #ifdef TARGET_ARM + static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + { +- abi_ulong val; + + switch (op) { + case TARGET_FREEBSD_ARM_SET_TP: Index: files/patch-z9b-bsd-user-sson003b @@ -0,0 +1,332 @@ +diff --git a/bsd-user/arm/target_vmparam.h b/bsd-user/arm/target_vmparam.h +index 0427244..24dca00 100644 +--- a/bsd-user/arm/target_vmparam.h ++++ b/bsd-user/arm/target_vmparam.h +@@ -20,6 +20,10 @@ struct target_ps_strings { + + #define TARGET_SZSIGCODE 0 + ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ + #else + + #define TARGET_USRSTACK 0 +diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c +index 0c48f5a..f5f652f 100644 +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -715,9 +715,13 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ ++#ifdef TARGET_STACK_SIZE ++ size = TARGET_STACK_SIZE; ++#else + size = x86_stack_size; + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; ++#endif + + #ifdef TARGET_USRSTACK + stack_base = TARGET_USRSTACK - size; +@@ -738,7 +742,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + + #if defined(__FreeBSD__) + /* +- * The inital FreeBSD stack looks like follows: ++ * The inital FreeBSD stack is as follows: + * (see kern/kern_exec.c exec_copyout_strings() ) + * + * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.) +diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list +index bcdd931..c66dcfa 100644 +--- a/bsd-user/freebsd/strace.list ++++ b/bsd-user/freebsd/strace.list +@@ -118,6 +118,7 @@ + { TARGET_FREEBSD_NR_revoke, "revoke", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_rfork, "rfork", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_rmdir, "rmdir", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_rtprio_thread, "rtprio_thread", "%s(%d, %d, %p)", NULL, NULL }, + { TARGET_FREEBSD_NR_sbrk, "sbrk", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_sched_yield, "sched_yield", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_select, "select", NULL, NULL, NULL }, +diff --git a/bsd-user/i386/target_vmparam.h b/bsd-user/i386/target_vmparam.h +index 8fc98d5..ea7546c 100644 +--- a/bsd-user/i386/target_vmparam.h ++++ b/bsd-user/i386/target_vmparam.h +@@ -19,6 +19,10 @@ struct target_ps_strings { + + #define TARGET_SZSIGCODE 0 + ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ + #else + + #define TARGET_USRSTACK 0 +diff --git a/bsd-user/main.c b/bsd-user/main.c +index 7cc77aa..32bd3e5 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -855,7 +855,9 @@ void cpu_loop(CPUARMState *env) + goto do_segv; + } + break; ++#if 0 + error: ++#endif + default: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); +diff --git a/bsd-user/mips/target_vmparam.h b/bsd-user/mips/target_vmparam.h +index 9fca7f3..8abc26c 100644 +--- a/bsd-user/mips/target_vmparam.h ++++ b/bsd-user/mips/target_vmparam.h +@@ -21,6 +21,10 @@ struct target_ps_strings { + + #define TARGET_SZSIGCODE 0 + ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ + #else + + #define TARGET_USRSTACK 0 +diff --git a/bsd-user/mips64/target_vmparam.h b/bsd-user/mips64/target_vmparam.h +index 47c2267..55ed254 100644 +--- a/bsd-user/mips64/target_vmparam.h ++++ b/bsd-user/mips64/target_vmparam.h +@@ -20,6 +20,10 @@ struct target_ps_strings { + + #define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) + ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ + #else + + #define TARGET_USRSTACK 0 +diff --git a/bsd-user/sparc/target_vmparam.h b/bsd-user/sparc/target_vmparam.h +index 9494c46..82c29ed 100644 +--- a/bsd-user/sparc/target_vmparam.h ++++ b/bsd-user/sparc/target_vmparam.h +@@ -1,8 +1,6 @@ + #ifndef _TARGET_VMPARAM_H_ + #define _TARGET_VMPARAM_H_ + +-#define TARGET_USRSTACK 0 +- + #ifdef __FreeBSD__ + struct target_ps_strings { + abi_ulong ps_argvstr; +@@ -14,9 +12,22 @@ struct target_ps_strings { + #define TARGET_SPACE_USRSPACE 4096 + #define TARGET_ARG_MAX 262144 + ++/* XXX */ ++#define TARGET_VM_MAXUSER_ADDRESS (0xc0000000 - (512 * 1024 * 1024)) ++#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS ++ + #define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) + + #define TARGET_SZSIGCODE 0 ++ ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ ++#else ++ ++#define TARGET_USRSTACK 0 ++ + #endif /* __FreeBSD__ */ + + #endif /* _TARGET_VMPARAM_H_ */ +diff --git a/bsd-user/sparc64/target_vmparam.h b/bsd-user/sparc64/target_vmparam.h +index 12af063..7f2b464 100644 +--- a/bsd-user/sparc64/target_vmparam.h ++++ b/bsd-user/sparc64/target_vmparam.h +@@ -21,6 +21,10 @@ struct target_ps_strings { + + #define TARGET_SZSIGCODE 0 + ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ + #else + + #define TARGET_USRSTACK 0 +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index a40d7ce..8565ae8 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -409,19 +409,44 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol + for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) + *q++ = tswap32(*p); + oidfmt(snamep, namelen, NULL, &kind); +- /* XXX swap hnewp */ +-#if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 +- /* XXX there may be more sysctls that differ */ +- if (namelen == 2 && +- snamep[0] == CTL_KERN && snamep[1] == KERN_USRSTACK && +- holdlen && holdlen == 4 && hnewp == NULL) { +- (*(uint32_t *)holdp) = 0xfffff000U; +- ret = 0; +- } else ++ ++ /* Handle some arch/emulator dependent sysctl()'s here. */ ++ if (CTL_KERN == snamep[0]) { ++ switch(snamep[1]) { ++ case KERN_USRSTACK: ++#if defined(TARGET_ARM) && HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 ++ (*(uint32_t *)holdp) = 0xfffff000U; ++ holdlen = sizeof(uint32_t); ++ ret = 0; ++#elif TARGET_USRSTACK != 0 ++ (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK); ++ holdlen = sizeof(abi_ulong); ++ ret = 0; ++#else ++ ret = -TARGET_ENOENT; ++#endif ++ goto out; ++ ++ case KERN_PS_STRINGS: ++#if defined(TARGET_PS_STRINGS) ++ (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS); ++ holdlen = sizeof(abi_ulong); ++ ret = 0; ++#else ++ ret = -TARGET_ENOENT; + #endif ++ goto out; ++ ++ default: ++ break; ++ } ++ } ++ + ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); + if (!ret) + sysctl_oldcvt(holdp, holdlen, kind); ++ ++out: + put_user_ual(holdlen, oldlenp); + unlock_user(hnamep, namep, 0); + unlock_user(holdp, oldp, holdlen); +@@ -3293,6 +3318,47 @@ host_to_target_fhandle(abi_ulong target_addr, fhandle_t *host_fh) + } + + static inline abi_long ++target_to_host_rtprio(struct rtprio *host_rtp, abi_ulong target_addr) ++{ ++ struct target_rtprio *target_rtp; ++ ++ if (!lock_user_struct(VERIFY_READ, target_rtp, target_addr, 1)) ++ return (-TARGET_EFAULT); ++ __get_user(host_rtp->type, &target_rtp->type); ++ __get_user(host_rtp->prio, &target_rtp->prio); ++ unlock_user_struct(target_rtp, target_addr, 0); ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_rtprio(abi_ulong target_addr, struct rtprio *host_rtp) ++{ ++ struct target_rtprio *target_rtp; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_rtp, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ __put_user(host_rtp->type, &target_rtp->type); ++ __put_user(host_rtp->prio, &target_rtp->prio); ++ unlock_user_struct(target_rtp, target_addr, 1); ++ return (0); ++} ++ ++static inline abi_long ++do_rtprio_thread(int function, lwpid_t lwpid, abi_ulong target_addr) ++{ ++ int ret; ++ struct rtprio rtp; ++ ++ ret = target_to_host_rtprio(&rtp, target_addr); ++ if (0 == ret) ++ ret = get_errno(rtprio_thread(function, lwpid, &rtp)); ++ if (0 == ret) ++ ret = host_to_target_rtprio(target_addr, &rtp); ++ ++ return (ret); ++} ++ ++static inline abi_long + target_to_host_sched_param(struct sched_param *host_sp, abi_ulong target_addr) + { + struct target_sched_param *target_sp; +@@ -4617,12 +4683,17 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + struct target_rlimit *target_rlim; + struct rlimit rlim; + +- if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) +- goto efault; +- rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur); +- rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max); +- unlock_user_struct(target_rlim, arg2, 0); +- ret = get_errno(setrlimit(resource, &rlim)); ++ if (RLIMIT_STACK == resource) { ++ /* XXX We should, maybe, allow the stack size to shrink */ ++ ret = -TARGET_EPERM; ++ } else { ++ if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) ++ goto efault; ++ rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur); ++ rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max); ++ unlock_user_struct(target_rlim, arg2, 0); ++ ret = get_errno(setrlimit(resource, &rlim)); ++ } + } + break; + +@@ -4633,7 +4704,12 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + struct target_rlimit *target_rlim; + struct rlimit rlim; + +- ret = get_errno(getrlimit(resource, &rlim)); ++ /* Return the target stack size */ ++ if (RLIMIT_STACK == resource) { ++ rlim.rlim_cur = rlim.rlim_max = TARGET_STACK_SIZE; ++ ret = 0; ++ } else ++ ret = get_errno(getrlimit(resource, &rlim)); + if (!is_error(ret)) { + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, + 0)) +@@ -6148,7 +6224,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + break; + + case TARGET_FREEBSD_NR_rtprio_thread: +- ret = 0; ++ ret = do_rtprio_thread(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getcontext: +diff --git a/bsd-user/x86_64/target_vmparam.h b/bsd-user/x86_64/target_vmparam.h +index aa5e0e0..ff9f534 100644 +--- a/bsd-user/x86_64/target_vmparam.h ++++ b/bsd-user/x86_64/target_vmparam.h +@@ -20,6 +20,10 @@ struct target_ps_strings { + + #define TARGET_SZSIGCODE 0 + ++/* Make stack size large enough to hold everything. */ ++#define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ ++ MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) ++ + #else + + #define TARGET_USRSTACK 0 Index: files/patch-z9c-bsd-user-sson003c @@ -0,0 +1,2425 @@ +diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c +index f5f652f..8abb1dd 100644 +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -403,8 +403,11 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i + { + + regs->cp0_status = 2 << CP0St_KSU; +- regs->regs[25] = regs->cp0_epc = infop->entry; /* t9 = pc = entry */ ++ regs->regs[25] = regs->cp0_epc = infop->entry & ~3; /* t9 = pc = entry */ + regs->regs[4] = regs->regs[29] = infop->start_stack; /* a0 = sp = start_stack */ ++ regs->regs[5] = 0; /* a1 = 0 */ ++ regs->regs[6] = 0; /* a2 = 0 */ ++ regs->regs[7] = TARGET_PS_STRINGS; /* a3 = ps_strings */ + } + + #define USE_ELF_CORE_DUMP +@@ -765,7 +768,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + { + abi_ulong stack_hi_addr; + size_t execpath_len; +- abi_ulong destp; ++ abi_ulong destp, argvp, envp; + struct target_ps_strings ps_strs; + char canary[sizeof(abi_long) * 8]; + char execpath[PATH_MAX]; +@@ -808,6 +811,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + /* XXX - check return value of put_user_ual(). */ + put_user_ual(TARGET_PAGE_SIZE, p); + ++ argvp = p - TARGET_SPACE_USRSPACE; + p = destp = p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX; + + /* XXX should check strlen(argv and envp strings) < TARGET_ARG_MAX */ +@@ -816,31 +820,38 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + * Add argv strings. Note that the argv[] vectors are added by + * loader_build_argptr() + */ ++ envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); ++ ps_strs.ps_argvstr = tswapl(argvp); ++ ps_strs.ps_nargvstr = tswap32(bprm->argc); + // i = bprm->argc; + // while (i-- > 0) { + for (i = 0; i < bprm->argc; ++i) { + size_t len = strlen(bprm->argv[i]) + 1; + /* XXX - check return value of memcpy_to_target(). */ + memcpy_to_target(destp, bprm->argv[i], len); ++ put_user_ual(destp, argvp); ++ argvp += sizeof(abi_ulong); + destp += len; + } +- ps_strs.ps_argvstr = tswapl(destp); +- ps_strs.ps_nargvstr = tswap32(bprm->argc); ++ put_user_ual(0, argvp); + + /* + * Add env strings. Note that the envp[] vectors are added by + * loader_build_argptr(). + */ ++ ps_strs.ps_envstr = tswapl(envp); ++ ps_strs.ps_nenvstr = tswap32(bprm->envc); + // i = bprm->envc; + // while(i-- > 0) { + for (i = 0; i < bprm->envc; ++i) { + size_t len = strlen(bprm->envp[i]) + 1; + /* XXX - check return value of memcpy_to_target(). */ + memcpy_to_target(destp, bprm->envp[i], len); ++ put_user_ual(destp, envp); ++ envp += sizeof(abi_ulong); + destp += len; + } +- ps_strs.ps_envstr = tswapl(destp); +- ps_strs.ps_nenvstr = tswap32(bprm->envc); ++ put_user_ual(0, envp); + + /* XXX - check return value of memcpy_to_target(). */ + memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs, +@@ -1304,6 +1315,27 @@ static void load_symbols(struct elfhdr *hdr, int fd) + syminfos = s; + } + ++/* Check the elf header and see if this a target elf binary. */ ++int is_target_elf_binary(int fd) ++{ ++ uint8_t buf[128]; ++ struct elfhdr elf_ex; ++ ++ if (lseek(fd, 0L, SEEK_SET) < 0) ++ return (0); ++ if (read(fd, buf, sizeof(buf)) < 0) ++ return (0); ++ ++ elf_ex = *((struct elfhdr *)buf); ++ bswap_ehdr(&elf_ex); ++ ++ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || ++ (! elf_check_arch(elf_ex.e_machine))) ++ return (0); ++ else ++ return (1); ++} ++ + int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) + { +@@ -1424,13 +1456,10 @@ int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + /* JRP - Need to add X86 lib dir stuff here... */ + + if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || +- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { ++ strcmp(elf_interpreter,"/libexec/ld-elf.so.1") == 0) { + ibcs2_interpreter = 1; + } + +-#if 0 +- printf("Using ELF interpreter %s\n", path(elf_interpreter)); +-#endif + if (retval >= 0) { + retval = open(path(elf_interpreter), O_RDONLY); + if(retval >= 0) { +diff --git a/bsd-user/freebsd/filio.h b/bsd-user/freebsd/filio.h +new file mode 100644 +index 0000000..2269484 +--- /dev/null ++++ b/bsd-user/freebsd/filio.h +@@ -0,0 +1,27 @@ ++#ifndef _FREEBSD_FILIO_H_ ++#define _FREEBSD_FILIO_H_ ++ ++/* see sys/filio.h */ ++#define TARGET_FIOCLEX TARGET_IO('f', 1) ++#define TARGET_FIONCLEX TARGET_IO('f', 2) ++#define TARGET_FIONREAD TARGET_IOR('f', 127, int) ++#define TARGET_FIONBIO TARGET_IOW('f', 126, int) ++#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) ++#define TARGET_FIOSETOWN TARGET_IOW('f', 124, int) ++#define TARGET_FIOGETOWN TARGET_IOR('f', 123, int) ++#define TARGET_FIODTYPE TARGET_IOR('f', 122, int) ++#define TARGET_FIOGETLBA TARGET_IOR('f', 121, int) ++ ++struct target_fiodgname_arg { ++ int32_t len; ++ abi_ulong buf; ++}; ++ ++#define TARGET_FIODGNAME TARGET_IOW('f', 120, \ ++ struct target_fiodgname_arg) ++#define TARGET_FIONWRITE TARGET_IOR('f', 119, int) ++#define TARGET_FIONSPACE TARGET_IOR('f', 118, int) ++#define TARGET_FIOSEEKDATA TARGET_IOWR('f', 97, off_t) ++#define TARGET_FIOSEEKHOLE TARGET_IOWR('f', 98, off_t) ++ ++#endif /* !_FREEBSD_FILIO_H_ */ +diff --git a/bsd-user/freebsd/ioctl.h b/bsd-user/freebsd/ioctl.h +deleted file mode 100644 +index f83f6c1..0000000 +--- a/bsd-user/freebsd/ioctl.h ++++ /dev/null +@@ -1,35 +0,0 @@ +-#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_R, MK_PTR(TYPE_INT)) +-IOCTL(TIOCSPGRP, IOC_W, 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/ioctls.h b/bsd-user/freebsd/ioctls.h +new file mode 100644 +index 0000000..85d3c41 +--- /dev/null ++++ b/bsd-user/freebsd/ioctls.h +@@ -0,0 +1,47 @@ ++ ++/* 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_R, MK_PTR(TYPE_INT)) ++IOCTL(TIOCSPGRP, IOC_W, 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)) ++ ++/* sys/filio.h */ ++IOCTL(FIOCLEX, IOC_, TYPE_NULL) ++IOCTL(FIONCLEX, IOC_, TYPE_NULL) ++IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(FIOSETOWN, IOC_W, MK_PTR(TYPE_INT)) ++IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(FIODTYPE, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(FIOGETLBA, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(FIODGNAME, IOC_R, MK_PTR(STRUCT_fiodgname_arg)) ++IOCTL(FIONWRITE, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(FIONSPACE, IOC_R, MK_PTR(TYPE_INT)) ++IOCTL(FIOSEEKDATA, IOC_RW, MK_PTR(TYPE_ULONG)) ++IOCTL(FIOSEEKHOLE, IOC_RW, MK_PTR(TYPE_ULONG)) +diff --git a/bsd-user/freebsd/strace.list b/bsd-user/freebsd/strace.list +index c66dcfa..8270c37 100644 +--- a/bsd-user/freebsd/strace.list ++++ b/bsd-user/freebsd/strace.list +@@ -1,7 +1,19 @@ ++{ TARGET_FREEBSD_NR___acl_aclcheck_fd, "__acl_get_fd", "%s(%d, %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_aclcheck_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_aclcheck_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_delete_fd, "__acl_delete_fd", "%s(%d, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_delete_file, "__acl_delete_file", "%s(\"%s\", %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_delete_link, "__acl_delete_link", "%s(\"%s\", %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_get_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_get_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_get_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_set_fd, "__acl_get_fd", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_set_file, "__acl_get_file", "%s(\"%s\", %d, %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR___acl_set_link, "__acl_get_link", "%s(\"%s\", %d, %#x)", NULL, NULL }, + { TARGET_FREEBSD_NR___getcwd, "__getcwd", NULL, NULL, NULL }, + { 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___sysctl, "__sysctl", NULL, print_sysctl, 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 }, +@@ -23,19 +35,34 @@ + { TARGET_FREEBSD_NR_dup2, "dup2", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_execve, "execve", NULL, print_execve, NULL }, + { TARGET_FREEBSD_NR_exit, "exit", "%s(%d)\n", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattrctl, "extattrctl", "%s(\"%s\", %d, \"%s\", %d, \"%s\"", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_delete_fd, "extattr_delete_fd", "%s(%d, %d, \"%s\")", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_delete_file, "extattr_delete_file", "%s(\"%s\", %d, \"%s\")", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_delete_link, "extattr_delete_link", "%s(\"%s\", %d, \"%s\")", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_get_fd, "extattr_get_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_get_file, "extattr_get_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_list_fd, "extattr_list_fd", "%s(%d, %d, %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_list_file, "extattr_list_file", "%s(\"%s\", %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_list_link, "extattr_list_link", "%s(\"%s\", %d, %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_set_fd, "extattr_set_fd", "%s(%d, %d, \"%s\", %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_set_file, "extattr_set_file", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_extattr_set_link, "extattr_set_link", "%s(\"%s\", %d, \"%s\", %#x, %d)", NULL, NULL }, + { TARGET_FREEBSD_NR_fchdir, "fchdir", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_fchflags, "fchflags", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_fchmod, "fchmod", "%s(%d,%#o)", NULL, NULL }, + { TARGET_FREEBSD_NR_fchown, "fchown", "%s(\"%s\",%d,%d)", NULL, NULL }, + { TARGET_FREEBSD_NR_fcntl, "fcntl", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_fexecve, "fexecve", NULL, print_execve, NULL }, + { TARGET_FREEBSD_NR_fhopen, "fhopen", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_fhstat, "fhstat", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_fhstatfs, "fhstatfs", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_flock, "flock", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_fork, "fork", "%s()", NULL, NULL }, + { TARGET_FREEBSD_NR_fpathconf, "fpathconf", NULL, NULL, NULL }, +-{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%p)", NULL, NULL }, +-{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%p)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_fstat, "fstat", "%s(%d,%#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_fstatat, "fstatat", "%s(%d,\"%s\", %#x)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_fstatfs, "fstatfs", "%s(%d,%#x)", NULL, NULL }, + { TARGET_FREEBSD_NR_fsync, "fsync", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL }, +@@ -65,7 +92,7 @@ + { TARGET_FREEBSD_NR_getsockopt, "getsockopt", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_gettimeofday, "gettimeofday", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_getuid, "getuid", "%s()", NULL, NULL }, +-{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_ioctl, "ioctl", NULL, print_ioctl, NULL }, + { TARGET_FREEBSD_NR_issetugid, "issetugid", "%s()", NULL, NULL }, + { TARGET_FREEBSD_NR_kevent, "kevent", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_kill, "kill", NULL, NULL, NULL }, +@@ -74,6 +101,7 @@ + { TARGET_FREEBSD_NR_lchown, "lchown", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_link, "link", "%s(\"%s\",\"%s\")", NULL, NULL }, + { TARGET_FREEBSD_NR_listen, "listen", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_lpathconf, "lpathconf", "%s(\"%s\", %d)", NULL, NULL }, + { TARGET_FREEBSD_NR_lseek, "lseek", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_lstat, "lstat", "%s(\"%s\",%p)", NULL, NULL }, + { TARGET_FREEBSD_NR_madvise, "madvise", NULL, NULL, NULL }, +@@ -98,7 +126,9 @@ + { TARGET_FREEBSD_NR_nanosleep, "nanosleep", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_nfssvc, "nfssvc", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_open, "open", "%s(\"%s\",%#x,%#o)", NULL, NULL }, ++{ TARGET_FREEBSD_NR_openat, "openat", "%s(%d, \"%s\",%#x,%#o)", NULL, NULL }, + { TARGET_FREEBSD_NR_pathconf, "pathconf", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_pathconf, "pathconf", "%s(\"%s\", %d)", NULL, NULL }, + { TARGET_FREEBSD_NR_pipe, "pipe", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_poll, "poll", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_pread, "pread", NULL, NULL, NULL }, +@@ -162,7 +192,7 @@ + { TARGET_FREEBSD_NR_statfs, "statfs", "%s(\"%s\",%p)", NULL, NULL }, + { TARGET_FREEBSD_NR_symlink, "symlink", "%s(\"%s\",\"%s\")", NULL, NULL }, + { TARGET_FREEBSD_NR_sync, "sync", NULL, NULL, NULL }, +-{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, NULL, NULL }, ++{ TARGET_FREEBSD_NR_sysarch, "sysarch", NULL, print_sysarch, NULL }, + { TARGET_FREEBSD_NR_syscall, "syscall", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_thr_create, "thr_create", NULL, NULL, NULL }, + { TARGET_FREEBSD_NR_thr_exit, "thr_exit", NULL, NULL, NULL }, +diff --git a/bsd-user/freebsd/syscall_types.h b/bsd-user/freebsd/syscall_types.h +index 6e43400..60b9288 100644 +--- a/bsd-user/freebsd/syscall_types.h ++++ b/bsd-user/freebsd/syscall_types.h +@@ -1,8 +1,7 @@ +-#ifndef _FREEBSD_SYSCALL_TYPES_H_ +-#define _FREEBSD_SYSCALL_TYPES_H_ + + STRUCT_SPECIAL(termios) + + STRUCT(winsize, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT) + +-#endif ++STRUCT(fiodgname_arg, TYPE_INT, TYPE_PTRVOID) ++ +diff --git a/bsd-user/main.c b/bsd-user/main.c +index 32bd3e5..bb614de 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -2,6 +2,7 @@ + * qemu user main + * + * Copyright (c) 2003-2008 Fabrice Bellard ++ * Copyright (c) 2012-2013 Stacey Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -25,6 +26,7 @@ + #include + #include + #include ++#include + + #include "qemu.h" + #include "qemu-common.h" +@@ -58,6 +60,36 @@ enum BSDType bsd_type; + by remapping the process stack directly at the right place */ + unsigned long x86_stack_size = 512 * 1024; + ++static void save_proc_pathname(void); ++char qemu_proc_pathname[PATH_MAX]; ++ ++#ifdef __FreeBSD__ ++static void ++save_proc_pathname(void) ++{ ++ int mib[4]; ++ size_t len; ++ ++ mib[0] = CTL_KERN; ++ mib[1] = KERN_PROC; ++ mib[2] = KERN_PROC_PATHNAME; ++ mib[3] = -1; ++ ++ len = sizeof(qemu_proc_pathname); ++ ++ if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) ++ perror("sysctl"); ++} ++ ++#else ++ ++static void ++save_proc_pathname(void) ++{ ++} ++ ++#endif /* !__FreeBSD__ */ ++ + void gemu_log(const char *fmt, ...) + { + va_list ap; +@@ -1496,6 +1528,8 @@ int main(int argc, char **argv) + if (argc <= 1) + usage(); + ++ save_proc_pathname(); ++ + module_call_init(MODULE_INIT_QOM); + + if ((envlist = envlist_create()) == NULL) { +diff --git a/bsd-user/mips64/target_signal.h b/bsd-user/mips64/target_signal.h +index e9c8a9f..c592136 100644 +--- a/bsd-user/mips64/target_signal.h ++++ b/bsd-user/mips64/target_signal.h +@@ -65,13 +65,7 @@ set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, + abi_ulong frame_addr, struct target_sigaction *ka) + { + +- frame->sf_signum = sig; +- frame->sf_siginfo = 0; +- frame->sf_ucontext = 0; +- +- frame->sf_si.si_signo = sig; +- frame->sf_si.si_code = TARGET_SA_SIGINFO; +- frame->sf_si.si_addr = regs->CP0_BadVAddr; ++ /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */ + + /* + * Arguments to signal handler: +@@ -86,6 +80,8 @@ set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, + regs->active_tc.gpr[ 4] = sig; + regs->active_tc.gpr[ 5] = frame_addr + + offsetof(struct target_sigframe, sf_si); ++ regs->active_tc.gpr[ 6] = frame_addr + ++ offsetof(struct target_sigframe, sf_uc); + regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; + regs->active_tc.gpr[29] = frame_addr; + regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; +diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h +index d9c9934..110b54e 100644 +--- a/bsd-user/qemu.h ++++ b/bsd-user/qemu.h +@@ -64,15 +64,15 @@ struct image_info { + + #define MAX_SIGQUEUE_SIZE 1024 + +-struct sigqueue { +- struct sigqueue *next; ++struct qemu_sigqueue { ++ struct qemu_sigqueue *next; + target_siginfo_t info; + }; + + struct emulated_sigtable { + int pending; /* true if signal is pending */ +- struct sigqueue *first; +- struct sigqueue info; /* in order to always have memory for the ++ struct qemu_sigqueue *first; ++ struct qemu_sigqueue info; /* in order to always have memory for the + first signal, we put it here */ + }; + +@@ -95,8 +95,8 @@ typedef struct TaskState { + struct bsd_binprm *bprm; + + struct emulated_sigtable sigtab[TARGET_NSIG]; +- struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ +- struct sigqueue *first_free; /* first free siginfo queue entry */ ++ struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ ++ struct qemu_sigqueue *first_free; /* first free siginfo queue entry */ + int signal_pending; /* non zero if a signal may be pending */ + + uint8_t stack[0]; +@@ -146,6 +146,7 @@ int load_elf_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); + int load_flt_binary(struct bsd_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); ++int is_target_elf_binary(int fd); + + void target_set_brk(abi_ulong new_brk); + abi_long do_brk(abi_ulong new_brk); +@@ -222,6 +223,7 @@ void mmap_fork_end(int child); + + /* main.c */ + extern unsigned long x86_stack_size; ++extern char qemu_proc_pathname[]; + + /* user access */ + +diff --git a/bsd-user/signal.c b/bsd-user/signal.c +index d56837b..29e8e12 100644 +--- a/bsd-user/signal.c ++++ b/bsd-user/signal.c +@@ -77,7 +77,7 @@ static uint8_t host_to_target_signal_table[_NSIG] = { + [SIGUSR1] = TARGET_SIGUSR1, + [SIGUSR2] = TARGET_SIGUSR2, + #ifdef SIGTHR +- [SIGTHR] = TARGET_SIGTHR, ++ [SIGTHR + 3] = TARGET_SIGTHR, + #endif + /* [SIGLWP] = TARGET_SIGLWP, */ + #ifdef SIGLIBRT +@@ -207,9 +207,10 @@ target_to_host_sigset(sigset_t *d, const target_sigset_t *s) + static inline void + host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) + { +- int sig; ++ int sig, code; + + sig = host_to_target_signal(info->si_signo); ++ code = tswap32(info->si_code); /* XXX should have host_to_target_si_code() */ + tinfo->si_signo = sig; + tinfo->si_errno = info->si_errno; + tinfo->si_code = info->si_code; +@@ -222,11 +223,13 @@ host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) + if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || + SIGBUS == sig || SIGTRAP == sig) { + tinfo->_reason._fault._trapno = info->_reason._fault._trapno; ++ } + #ifdef SIGPOLL +- } else if (SIGPOLL == sig) { ++ if (SIGPOLL == sig) { + tinfo->_reason._poll._band = info->_reason._poll._band; ++ } + #endif +- } else { ++ if (SI_TIMER == code) { + tinfo->_reason._timer._timerid = info->_reason._timer._timerid; + tinfo->_reason._timer._overrun = info->_reason._timer._overrun; + } +@@ -235,8 +238,10 @@ host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) + static void + tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) + { +- int sig; ++ int sig, code; ++ + sig = info->si_signo; ++ code = info->si_code; + tinfo->si_signo = tswap32(sig); + tinfo->si_errno = tswap32(info->si_errno); + tinfo->si_code = tswap32(info->si_code); +@@ -247,11 +252,13 @@ tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) + SIGBUS == sig || SIGTRAP == sig) { + tinfo->_reason._fault._trapno = + tswap32(info->_reason._fault._trapno); ++ } + #ifdef SIGPOLL +- } else if (SIGPOLL == sig) { ++ if (SIGPOLL == sig) { + tinfo->_reason._poll._band = tswap32(info->_reason._poll._band); ++ } + #endif +- } else { ++ if (SI_TIMER == code) { + tinfo->_reason._timer._timerid = + tswap32(info->_reason._timer._timerid); + tinfo->_reason._timer._overrun = +@@ -286,11 +293,11 @@ core_dump_signal(int sig) + } + + /* Signal queue handling. */ +-static inline struct sigqueue * ++static inline struct qemu_sigqueue * + alloc_sigqueue(CPUArchState *env) + { + TaskState *ts = env->opaque; +- struct sigqueue *q = ts->first_free; ++ struct qemu_sigqueue *q = ts->first_free; + + if (!q) + return (NULL); +@@ -299,7 +306,7 @@ alloc_sigqueue(CPUArchState *env) + } + + static inline void +-free_sigqueue(CPUArchState *env, struct sigqueue *q) ++free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q) + { + + TaskState *ts = env->opaque; +@@ -372,7 +379,7 @@ queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) + { + TaskState *ts = env->opaque; + struct emulated_sigtable *k; +- struct sigqueue *q, **pq; ++ struct qemu_sigqueue *q, **pq; + abi_ulong handler; + int queue; + +@@ -606,7 +613,7 @@ do_sigaction(int sig, const struct target_sigaction *act, + return (ret); + } + +-#if defined(TARGET_MIPS) || defined(TARGET_SPARC64) ++#if defined(TARGET_MIPS64) /* || defined(TARGET_SPARC64) */ + + static inline abi_ulong + get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) +@@ -629,8 +636,8 @@ get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) + } + + /* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */ +-static void setup_frame(int sig, struct target_sigaction *ka, +- target_sigset_t *set, CPUArchState *regs) ++static void setup_frame(int sig, int code, struct target_sigaction *ka, ++ target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs) + { + struct target_sigframe *frame; + abi_ulong frame_addr; +@@ -651,6 +658,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto give_sigsegv; + ++ memset(frame, 0, sizeof(*frame)); + #if defined(TARGET_MIPS) + int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC : + TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC; +@@ -666,6 +674,58 @@ static void setup_frame(int sig, struct target_sigaction *ka, + goto give_sigsegv; + } + ++ if (tinfo) { ++ frame->sf_si.si_signo = tinfo->si_signo; ++ frame->sf_si.si_errno = tinfo->si_errno; ++ frame->sf_si.si_code = tinfo->si_code; ++ frame->sf_si.si_pid = tinfo->si_pid; ++ frame->sf_si.si_uid = tinfo->si_uid; ++ frame->sf_si.si_status = tinfo->si_status; ++ frame->sf_si.si_addr = tinfo->si_addr; ++ ++ if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig || ++ TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig || ++ TARGET_SIGTRAP == sig) ++ frame->sf_si._reason._fault._trapno = ++ tinfo->_reason._fault._trapno; ++ ++ /* ++ * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or ++ * SI_MESGQ, then si_value contains the application-specified ++ * signal value. Otherwise, the contents of si_value are ++ * undefined. ++ */ ++ if (SI_QUEUE == code || SI_TIMER == code || ++ SI_ASYNCIO == code || SI_MESGQ == code) { ++ frame->sf_si.si_value.sival_int = ++ tinfo->si_value.sival_int; ++ } ++ ++ if (SI_TIMER == code) { ++ frame->sf_si._reason._timer._timerid = ++ tinfo->_reason._timer._timerid; ++ frame->sf_si._reason._timer._overrun = ++ tinfo->_reason._timer._overrun; ++ } ++ ++#ifdef SIGPOLL ++ if (SIGPOLL == sig) { ++ frame->sf_si._reason._band = ++ tinfo->_reason._band; ++ } ++#endif ++ ++ frame->sf_signum = sig; ++ frame->sf_siginfo = (abi_ulong)&frame->sf_si; ++ frame->sf_ucontext = (abi_ulong)&frame->sf_uc; ++ ++ } else { ++ frame->sf_signum = sig; ++ frame->sf_siginfo = 0; ++ frame->sf_ucontext = 0; ++ } ++ ++ + if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) + goto give_sigsegv; + +@@ -866,8 +926,8 @@ get_sigframe(struct target_sigaction *ka, CPUSPARCState *regs, size_t frame_size + } + + /* compare to sparc64/sparc64/machdep.c sendsig() */ +-static void setup_frame(int sig, struct target_sigaction *ka, +- target_sigset_t *set, CPUSPARCState *regs) ++static void setup_frame(int sig, int code, struct target_sigaction *ka, ++ target_sigset_t *set, target_siginfo_t *tinfo, CPUSPARCState *regs) + { + struct target_sigframe *frame; + abi_ulong frame_addr; +@@ -960,21 +1020,12 @@ badframe: + #else + + static void +-setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, +- CPUArchState *env) ++setup_frame(int sig, int code, struct target_sigaction *ka, target_sigset_t *set, ++ target_siginfo_t *tinfo, CPUArchState *env) + { + fprintf(stderr, "setup_frame: not implemented\n"); + } + +-#if 0 +-static void +-setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, +- target_sigset_t *set, CPUArchState *env) +-{ +- fprintf(stderr, "setup_rt_frame: not implemented\n"); +-} +-#endif +- + long + do_sigreturn(CPUArchState *env, abi_ulong uc_addr) + { +@@ -1043,13 +1094,14 @@ signal_init(void) + void + process_pending_signals(CPUArchState *cpu_env) + { +- int sig; ++ int sig, code; + abi_ulong handler; + sigset_t set, old_set; + target_sigset_t target_old_set; ++ target_siginfo_t tinfo; + struct emulated_sigtable *k; + struct target_sigaction *sa; +- struct sigqueue *q; ++ struct qemu_sigqueue *q; + TaskState *ts = cpu_env->opaque; + + if (!ts->signal_pending) +@@ -1143,14 +1195,16 @@ handle_signal: + } + #endif + #endif ++ code = q->info.si_code; + /* prepare the stack frame of the virtual CPU */ +-#if 0 /* XXX no rt for fbsd */ +- if (sa->sa_flags & TARGET_SA_SIGINFO) +- setup_rt_frame(sig, sa, &q->info, &target_old_set, ++ if (sa->sa_flags & TARGET_SA_SIGINFO) { ++ tswap_siginfo(&tinfo, &q->info); ++ setup_frame(sig, code, sa, &target_old_set, &tinfo, + cpu_env); +- else +-#endif +- setup_frame(sig, sa, &target_old_set, cpu_env); ++ } else { ++ setup_frame(sig, code, sa, &target_old_set, NULL, ++ cpu_env); ++ } + if (sa->sa_flags & TARGET_SA_RESETHAND) + sa->_sa_handler = TARGET_SIG_DFL; + } +diff --git a/bsd-user/strace.c b/bsd-user/strace.c +index d73bbca..7f0f7bd 100644 +--- a/bsd-user/strace.c ++++ b/bsd-user/strace.c +@@ -4,7 +4,12 @@ + #include + #include + #include ++#include ++#include + #include "qemu.h" ++#ifdef __FreeBSD__ ++#include "freebsd/syscall_nr.h" ++#endif + + int do_strace=0; + +@@ -23,6 +28,29 @@ struct syscallname { + */ + + static void ++print_sysctl(const struct syscallname *name, ++ abi_long arg1, abi_long arg2, abi_long arg3, ++ abi_long arg4, abi_long arg5, abi_long arg6) ++{ ++ uint32_t i; ++ int32_t *namep; ++ ++ ++ gemu_log("%s({ ", name->name); ++ namep = lock_user(VERIFY_READ, arg1, sizeof(int32_t) * arg2, 1); ++ if (namep) { ++ int32_t *p = namep; ++ ++ for(i = 0; i < (uint32_t)arg2; i++) ++ gemu_log("%d ", tswap32(*p++)); ++ unlock_user(namep, arg1, 0); ++ } ++ gemu_log("}, %u, 0x" TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ", 0x" ++ TARGET_ABI_FMT_lx ", 0x" TARGET_ABI_FMT_lx ")", ++ (uint32_t)arg2, arg3, arg4, arg5, arg6); ++} ++ ++static void + print_execve(const struct syscallname *name, + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) +@@ -30,10 +58,18 @@ print_execve(const struct syscallname *name, + abi_ulong arg_ptr_addr; + char *s; + +- if (!(s = lock_user_string(arg1))) +- return; +- gemu_log("%s(\"%s\",{", name->name, s); +- unlock_user(s, arg1, 0); ++#ifdef __FreeBSD__ ++ if (TARGET_FREEBSD_NR_fexecve == name->nr) { ++ gemu_log("%s(%d,{", name->name, (int)arg1); ++ ++ } else ++#endif ++ { ++ if (!(s = lock_user_string(arg1))) ++ return; ++ gemu_log("%s(\"%s\",{", name->name, s); ++ unlock_user(s, arg1, 0); ++ } + + for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { + abi_ulong *arg_ptr, arg_addr; +@@ -54,6 +90,54 @@ print_execve(const struct syscallname *name, + gemu_log("NULL})"); + } + ++static void ++print_ioctl(const struct syscallname *name, ++ abi_long arg1, abi_long arg2, abi_long arg3, ++ abi_long arg4, abi_long arg5, abi_long arg6) ++{ ++ /* Decode the ioctl request */ ++ gemu_log("%s(%d, 0x%0lx { IO%s%s GRP:0x%x('%c') CMD:%d LEN:%d }, 0x" ++ TARGET_ABI_FMT_lx ", ...)", ++ ++ name->name, ++ (int)arg1, ++ (unsigned long)arg2, ++ arg2 & IOC_OUT ? "R" : "", ++ arg2 & IOC_IN ? "W" : "", ++ (unsigned)IOCGROUP(arg2), ++ isprint(IOCGROUP(arg2)) ? (char)IOCGROUP(arg2) : '?', ++ (int)arg2 & 0xFF, ++ (int)IOCPARM_LEN(arg2), ++ arg3); ++} ++ ++static void ++print_sysarch(const struct syscallname *name, ++ abi_long arg1, abi_long arg2, abi_long arg3, ++ abi_long arg4, abi_long arg5, abi_long arg6) ++{ ++#ifdef TARGET_MIPS ++ switch(arg1) { ++ case 1: ++ gemu_log("%s(SET_TLS, 0x" TARGET_ABI_FMT_lx ")", ++ name->name, arg2); ++ break; ++ ++ case 2: ++ gemu_log("%s(GET_TLS, 0x" TARGET_ABI_FMT_lx ")", ++ name->name, arg2); ++ break; ++ ++ default: ++ gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", ++ (int)arg1, arg2); ++ } ++#else ++ gemu_log("%s(%d, " TARGET_ABI_FMT_lx ", " TARGET_ABI_FMT_lx ", " ++ TARGET_ABI_FMT_lx ")", name->name, (int)arg1, arg2, arg3, arg4); ++#endif ++} ++ + /* + * Variants for the return value output function + */ +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index 8565ae8..74b5c86 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -2,7 +2,7 @@ + * BSD syscalls + * + * Copyright (c) 2003 - 2008 Fabrice Bellard +- * Copyright (c) 2012 Stacey Son ++ * Copyright (c) 2012 - 2013 Stacey Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -68,8 +69,12 @@ + #include + #endif + #include ++#include + #include + #include ++#define _ACL_PRIVATE ++#include ++#include + #include + #include + #include +@@ -87,6 +92,7 @@ + #include "qemu-common.h" + #ifdef __FreeBSD__ + #include "freebsd/ttycom.h" ++#include "freebsd/filio.h" + #endif + + +@@ -95,6 +101,70 @@ + static abi_ulong target_brk; + static abi_ulong target_original_brk; + ++static char *get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len); ++ ++#ifdef __FreeBSD__ ++#include ++#include ++#include ++ ++ ++/* ++ * Get the filename for the given file descriptor. ++ * Note that this may return NULL (fail) if no longer cached in the kernel. ++ */ ++static char * ++get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) ++{ ++ unsigned int cnt; ++ struct procstat *procstat = NULL; ++ struct kinfo_proc *kipp = NULL; ++ struct filestat_list *head = NULL; ++ struct filestat *fst; ++ char *ret = NULL; ++ ++ procstat = procstat_open_sysctl(); ++ if (NULL == procstat) ++ goto out; ++ ++ kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt); ++ if (NULL == kipp) ++ goto out; ++ ++ head = procstat_getfiles(procstat, kipp, 0); ++ if (NULL == head) ++ goto out; ++ ++ STAILQ_FOREACH(fst, head, next) { ++ if (fd == fst->fs_fd) { ++ if (fst->fs_path != NULL) { ++ (void)strlcpy(filename, fst->fs_path, len); ++ ret = filename; ++ } ++ break; ++ } ++ } ++ ++out: ++ if (head != NULL) ++ procstat_freefiles(procstat, head); ++ if (kipp != NULL) ++ procstat_freeprocs(procstat, kipp); ++ if (procstat != NULL) ++ procstat_close(procstat); ++ return (ret); ++} ++ ++#else ++ ++static char * ++get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len) ++{ ++ return (NULL); ++} ++ ++#endif /* ! __FreeBSD__ */ ++ + static inline abi_long get_errno(abi_long ret) + { + if (ret == -1) +@@ -297,9 +367,9 @@ static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms) + + switch(op) { + case TARGET_MIPS_SET_TLS: +- if (get_user(mips_env->tls_value, parms, abi_ulong)) +- ret = -TARGET_EFAULT; ++ mips_env->tls_value = parms; + break; ++ + case TARGET_MIPS_GET_TLS: + if (put_user(mips_env->tls_value, parms, abi_ulong)) + ret = -TARGET_EFAULT; +@@ -386,24 +456,46 @@ static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) + return 0; + } + ++/* ++ * Convert the undocmented name2oid sysctl data for the target. ++ */ ++static inline void ++sysctl_name2oid(uint32_t *holdp, size_t holdlen) ++{ ++ size_t i; ++ ++ for(i = 0; i < holdlen; i++) ++ holdp[i] = tswap32(holdp[i]); ++} ++ ++static inline void ++sysctl_oidfmt(uint32_t *holdp) ++{ ++ /* byte swap the kind */ ++ holdp[0] = tswap32(holdp[0]); ++} ++ + /* XXX this needs to be emulated on non-FreeBSD hosts... */ + static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp, + abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) + { + abi_long ret; +- void *hnamep, *holdp, *hnewp = NULL; ++ void *hnamep, *holdp = NULL, *hnewp = NULL; + size_t holdlen; + abi_ulong oldlen = 0; + int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; + uint32_t kind = 0; ++ abi_ulong argv, argv0; ++ char *fullpath = NULL; + + if (oldlenp) +- get_user_ual(oldlen, oldlenp); ++ if (get_user_ual(oldlen, oldlenp)) ++ return -TARGET_EFAULT; + if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1))) + return -TARGET_EFAULT; + if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1))) + return -TARGET_EFAULT; +- if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) ++ if (oldp && !(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) + return -TARGET_EFAULT; + holdlen = oldlen; + for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) +@@ -411,7 +503,8 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol + oidfmt(snamep, namelen, NULL, &kind); + + /* Handle some arch/emulator dependent sysctl()'s here. */ +- if (CTL_KERN == snamep[0]) { ++ switch(snamep[0]) { ++ case CTL_KERN: + switch(snamep[1]) { + case KERN_USRSTACK: + #if defined(TARGET_ARM) && HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 +@@ -437,17 +530,77 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol + #endif + goto out; + ++ case KERN_PROC: ++ switch(snamep[2]) { ++ case KERN_PROC_PATHNAME: ++ if (get_user_ual(argv, TARGET_PS_STRINGS)) { ++ ret = -TARGET_EFAULT; ++ goto out; ++ } ++ if (get_user_ual(argv0, argv)) { ++ ret = -TARGET_EFAULT; ++ goto out; ++ } ++ ++ fullpath = realpath(g2h(argv0), NULL); ++ if (NULL == fullpath) ++ fullpath = (char *)g2h(argv0); ++ holdlen = strlen(fullpath) + 1; ++ if (holdp) { ++ if (oldlen < holdlen) { ++ ret = -TARGET_EINVAL; ++ goto out; ++ } ++ if (!access_ok(VERIFY_WRITE, argv0, ++ holdlen)) { ++ ret = -TARGET_EFAULT; ++ goto out; ++ } ++ strlcpy(holdp, fullpath, oldlen); ++ } ++ ret = 0; ++ goto out; ++ ++ default: ++ break; ++ } ++ break; ++ + default: + break; + } ++ break; ++ ++ default: ++ break; + } + + ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); +- if (!ret) +- sysctl_oldcvt(holdp, holdlen, kind); ++ if (!ret && (holdp != 0 && holdlen != 0)) { ++ if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) { ++ if (3 == snamep[1]) { ++ /* Handle the undocumented name2oid special case. */ ++ sysctl_name2oid(holdp, holdlen); ++ } else { ++ /* Handle oidfmt */ ++ sysctl_oidfmt(holdp); ++ } ++ } else { ++ sysctl_oldcvt(holdp, holdlen, kind); ++ } ++ } ++#ifdef DEBUG ++ else { ++ printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n", ++ snamep[0], snamep[1], snamep[2], (int)ret); ++ } ++#endif + + out: +- put_user_ual(holdlen, oldlenp); ++ if (fullpath) ++ free(fullpath); ++ if (oldlenp) ++ put_user_ual(holdlen, oldlenp); + unlock_user(hnamep, namep, 0); + unlock_user(holdp, oldp, holdlen); + if (hnewp) +@@ -509,6 +662,24 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, + } + + static inline abi_long ++target_to_host_ip_mreq(struct ip_mreqn *mreqn, abi_ulong target_addr, ++ socklen_t len) ++{ ++ struct target_ip_mreqn *target_smreqn; ++ ++ target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1); ++ if (!target_smreqn) ++ return -TARGET_EFAULT; ++ mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; ++ mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; ++ if (len == sizeof(struct target_ip_mreqn)) ++ mreqn->imr_ifindex = tswapal(target_smreqn->imr_ifindex); ++ unlock_user(target_smreqn, target_addr, 0); ++ ++ return (0); ++} ++ ++static inline abi_long + target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, + socklen_t len) + { +@@ -1554,11 +1725,62 @@ int_case: + } + break; + ++ case IPPROTO_TCP: ++ /* TCP options all take an 'int' value. */ ++ goto int_case; ++ ++ case IPPROTO_IP: ++ switch(optname) { ++ case IP_HDRINCL: ++ case IP_TOS: ++ case IP_TTL: ++ case IP_RECVOPTS: ++ case IP_RECVRETOPTS: ++ case IP_RECVDSTADDR: ++ ++ case IP_RETOPTS: ++ case IP_RECVTOS: ++ case IP_MULTICAST_TTL: ++ case IP_MULTICAST_LOOP: ++ case IP_PORTRANGE: ++ case IP_IPSEC_POLICY: ++ case IP_FAITH: ++ case IP_ONESBCAST: ++ case IP_BINDANY: ++ if (get_user_u32(len, optlen)) ++ return (-TARGET_EFAULT); ++ if (len < 0) ++ return (-TARGET_EINVAL); ++ lv = sizeof(lv); ++ ret = get_errno(getsockopt(sockfd, level, optname, ++ &val, &lv)); ++ if (ret < 0) ++ return (ret); ++ if (len < sizeof(int) && len > 0 && val >= 0 && ++ val < 255) { ++ len = 1; ++ if (put_user_u32(len, optlen) ++ || put_user_u8(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ } else { ++ if (len > sizeof(int)) ++ len = sizeof(int); ++ if (put_user_u32(len, optlen) ++ || put_user_u32(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ } ++ break; ++ ++ default: ++ goto unimplemented; ++ } ++ break; ++ + default: + unimplemented: + gemu_log("getsockopt level=%d optname=%d not yet supported\n", + level, optname); +- ret = -TARGET_EOPNOTSUPP; ++ ret = (-TARGET_EOPNOTSUPP); + break; + } + return (ret); +@@ -1569,10 +1791,67 @@ static abi_long + do_setsockopt(int sockfd, int level, int optname, abi_ulong optval_addr, + socklen_t optlen) + { +- int val; + abi_long ret; ++ int val; ++ struct ip_mreqn *ip_mreq; + + switch(level) { ++ case IPPROTO_TCP: ++ /* TCP options all take an 'int' value. */ ++ if (optlen < sizeof(uint32_t)) ++ return (-TARGET_EINVAL); ++ ++ if (get_user_u32(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ ret = get_errno(setsockopt(sockfd, level, optname, &val, ++ sizeof(val))); ++ break; ++ ++ case IPPROTO_IP: ++ switch (optname) { ++ case IP_HDRINCL:/* int; header is included with data */ ++ case IP_TOS: /* int; IP type of service and preced. */ ++ case IP_TTL: /* int; IP time to live */ ++ case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */ ++ case IP_RECVRETOPTS: /* bool; receive IP opts for response */ ++ case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */ ++ case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f */ ++ case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */ ++ case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */ ++ case IP_PORTRANGE: /* int; range to choose for unspec port */ ++ case IP_RECVIF: /* bool; receive reception if w/dgram */ ++ case IP_IPSEC_POLICY: /* int; set/get security policy */ ++ case IP_FAITH: /* bool; accept FAITH'ed connections */ ++ case IP_RECVTTL: /* bool; receive reception TTL w/dgram */ ++ val = 0; ++ if (optlen >= sizeof(uint32_t)) { ++ if (get_user_u32(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ } else if (optlen >= 1) { ++ if (get_user_u8(val, optval_addr)) ++ return (-TARGET_EFAULT); ++ } ++ ret = get_errno(setsockopt(sockfd, level, optname, ++ &val, sizeof(val))); ++ break; ++ ++ case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */ ++ case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group membership*/ ++ if (optlen < sizeof (struct target_ip_mreq) || ++ optlen > sizeof (struct target_ip_mreqn)) ++ return (-TARGET_EINVAL); ++ ip_mreq = (struct ip_mreqn *) alloca(optlen); ++ target_to_host_ip_mreq(ip_mreq, optval_addr, optlen); ++ ret = get_errno(setsockopt(sockfd, level, optname, ++ ip_mreq, optlen)); ++ break; ++ ++ default: ++ goto unimplemented; ++ } ++ break; ++ ++ + case TARGET_SOL_SOCKET: + switch (optname) { + /* Options with 'int' argument. */ +@@ -1730,13 +2009,15 @@ target_to_host_semarray(int semid, unsigned short **host_array, + if (ret == -1) + return (get_errno(ret)); + nsems = semid_ds.sem_nsems; +- *host_array = malloc(nsems * sizeof(unsigned short)); ++ *host_array = (unsigned short *)malloc(nsems * sizeof(unsigned short)); + array = lock_user(VERIFY_READ, target_addr, + nsems*sizeof(unsigned short), 1); +- if (!array) ++ if (!array) { ++ free(*host_array); + return (-TARGET_EFAULT); ++ } + for(i=0; isem_perm); +- host_ip->cuid = tswapal(target_ip->cuid); +- host_ip->cgid = tswapal(target_ip->cgid); +- host_ip->uid = tswapal(target_ip->uid); +- host_ip->gid = tswapal(target_ip->gid); ++ host_ip->cuid = tswap32(target_ip->cuid); ++ host_ip->cgid = tswap32(target_ip->cgid); ++ host_ip->uid = tswap32(target_ip->uid); ++ host_ip->gid = tswap32(target_ip->gid); + host_ip->mode = tswap16(target_ip->mode); + host_ip->seq = tswap16(target_ip->seq); + host_ip->key = tswapal(target_ip->key); +- unlock_user_struct(target_sd, target_addr, 0); ++ unlock_user_struct(target_ip, target_addr, 0); + + return (0); + } +@@ -1800,18 +2082,17 @@ static inline abi_long + host_to_target_ipc_perm(abi_ulong target_addr, struct ipc_perm *host_ip) + { + struct target_ipc_perm *target_ip; +- struct target_semid_ds *target_sd; +- if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_ip, target_addr, 0)) + return (-TARGET_EFAULT); +- target_ip = &(target_sd->sem_perm); +- target_ip->cuid = tswapal(host_ip->cuid); +- target_ip->cgid = tswapal(host_ip->cgid); +- target_ip->uid = tswapal(host_ip->uid); +- target_ip->gid = tswapal(host_ip->gid); ++ target_ip->cuid = tswap32(host_ip->cuid); ++ target_ip->cgid = tswap32(host_ip->cgid); ++ target_ip->uid = tswap32(host_ip->uid); ++ target_ip->gid = tswap32(host_ip->gid); + target_ip->mode = tswap16(host_ip->mode); + target_ip->seq = tswap16(host_ip->seq); + target_ip->key = tswapal(host_ip->key); +- unlock_user_struct(target_sd, target_addr, 1); ++ unlock_user_struct(target_ip, target_addr, 1); + return (0); + } + +@@ -1822,11 +2103,12 @@ target_to_host_semid_ds(struct semid_ds *host_sd, abi_ulong target_addr) + + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return (-TARGET_EFAULT); +- if (target_to_host_ipc_perm(&(host_sd->sem_perm), target_addr)) ++ if (target_to_host_ipc_perm(&(host_sd->sem_perm), (target_addr + ++ offsetof(struct target_semid_ds, sem_perm)) )) + return (-TARGET_EFAULT); + /* sem_base is not used by kernel for IPC_STAT/IPC_SET */ +- host_sd->sem_base = NULL; +- host_sd->sem_nsems = tswapal(target_sd->sem_nsems); ++ /* host_sd->sem_base = g2h(target_sd->sem_base); */ ++ host_sd->sem_nsems = tswap16(target_sd->sem_nsems); + host_sd->sem_otime = tswapal(target_sd->sem_otime); + host_sd->sem_ctime = tswapal(target_sd->sem_ctime); + unlock_user_struct(target_sd, target_addr, 0); +@@ -1840,10 +2122,13 @@ host_to_target_semid_ds(abi_ulong target_addr, struct semid_ds *host_sd) + + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return (-TARGET_EFAULT); +- if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm))) ++ if (host_to_target_ipc_perm((target_addr + ++ offsetof(struct target_semid_ds, sem_perm)), ++ &(host_sd->sem_perm))) + return (-TARGET_EFAULT); + /* sem_base is not used by kernel for IPC_STAT/IPC_SET */ +- target_sd->sem_nsems = tswapal(host_sd->sem_nsems); ++ /* target_sd->sem_base = h2g((void *)host_sd->sem_base); */ ++ target_sd->sem_nsems = tswap16(host_sd->sem_nsems); + target_sd->sem_otime = tswapal(host_sd->sem_otime); + target_sd->sem_ctime = tswapal(host_sd->sem_ctime); + unlock_user_struct(target_sd, target_addr, 1); +@@ -1859,6 +2144,7 @@ do_semctl(int semid, int semnum, int cmd, union target_semun target_su) + unsigned short *array = NULL; + abi_long ret = -TARGET_EINVAL; + abi_long err; ++ abi_ulong target_addr; + + cmd &= 0xff; + +@@ -1872,24 +2158,28 @@ do_semctl(int semid, int semnum, int cmd, union target_semun target_su) + + case GETALL: + case SETALL: +- err = target_to_host_semarray(semid, &array, target_su.array); ++ if (get_user_ual(target_addr, (abi_ulong)target_su.array)) ++ return (-TARGET_EFAULT); ++ err = target_to_host_semarray(semid, &array, target_addr); + if (err) + return (err); + arg.array = array; + ret = get_errno(semctl(semid, semnum, cmd, arg)); +- err = host_to_target_semarray(semid, target_su.array, &array); ++ err = host_to_target_semarray(semid, target_addr, &array); + if (err) + return (err); + break; + + case IPC_STAT: + case IPC_SET: +- err = target_to_host_semid_ds(&dsarg, target_su.buf); ++ if (get_user_ual(target_addr, (abi_ulong)target_su.buf)) ++ return (-TARGET_EFAULT); ++ err = target_to_host_semid_ds(&dsarg, target_addr); + if (err) + return (err); + arg.buf = &dsarg; + ret = get_errno(semctl(semid, semnum, cmd, arg)); +- err = host_to_target_semid_ds(target_su.buf, &dsarg); ++ err = host_to_target_semid_ds(target_addr, &dsarg); + if (err) + return (err); + break; +@@ -3383,6 +3673,64 @@ host_to_target_sched_param(abi_ulong target_addr, struct sched_param *host_sp) + } + + static inline abi_long ++target_to_host_acl(struct acl *host_acl, abi_ulong target_addr) ++{ ++ uint32_t i; ++ struct target_acl *target_acl; ++ ++ if (!lock_user_struct(VERIFY_READ, target_acl, target_addr, 1)) ++ return (-TARGET_EFAULT); ++ ++ __get_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt); ++ __get_user(host_acl->acl_cnt, &target_acl->acl_cnt); ++ ++ for(i = 0; i < host_acl->acl_maxcnt; i++) { ++ __get_user(host_acl->acl_entry[i].ae_tag, ++ &target_acl->acl_entry[i].ae_tag); ++ __get_user(host_acl->acl_entry[i].ae_id, ++ &target_acl->acl_entry[i].ae_id); ++ __get_user(host_acl->acl_entry[i].ae_perm, ++ &target_acl->acl_entry[i].ae_perm); ++ __get_user(host_acl->acl_entry[i].ae_entry_type, ++ &target_acl->acl_entry[i].ae_entry_type); ++ __get_user(host_acl->acl_entry[i].ae_flags, ++ &target_acl->acl_entry[i].ae_flags); ++ } ++ ++ unlock_user_struct(target_acl, target_addr, 0); ++ return (0); ++} ++ ++static inline abi_long ++host_to_target_acl(abi_ulong target_addr, struct acl *host_acl) ++{ ++ uint32_t i; ++ struct target_acl *target_acl; ++ ++ if (!lock_user_struct(VERIFY_WRITE, target_acl, target_addr, 0)) ++ return (-TARGET_EFAULT); ++ ++ __put_user(host_acl->acl_maxcnt, &target_acl->acl_maxcnt); ++ __put_user(host_acl->acl_cnt, &target_acl->acl_cnt); ++ ++ for(i = 0; i < host_acl->acl_maxcnt; i++) { ++ __put_user(host_acl->acl_entry[i].ae_tag, ++ &target_acl->acl_entry[i].ae_tag); ++ __put_user(host_acl->acl_entry[i].ae_id, ++ &target_acl->acl_entry[i].ae_id); ++ __put_user(host_acl->acl_entry[i].ae_perm, ++ &target_acl->acl_entry[i].ae_perm); ++ __get_user(host_acl->acl_entry[i].ae_entry_type, ++ &target_acl->acl_entry[i].ae_entry_type); ++ __get_user(host_acl->acl_entry[i].ae_flags, ++ &target_acl->acl_entry[i].ae_flags); ++ } ++ ++ unlock_user_struct(target_acl, target_addr, 1); ++ return (0); ++} ++ ++static inline abi_long + do_sched_setparam(pid_t pid, abi_ulong target_sp_addr) + { + int ret; +@@ -3993,10 +4341,10 @@ static IOCTLEntry ioctl_entries[] = { + { 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" ++#if defined(__FreeBSD__) ++#include "freebsd/ioctls.h" + #else +-#warning No ioctl.h ++#warning No *bsd/ioctls.h + #endif + { 0, 0 }, + }; +@@ -4096,6 +4444,158 @@ do_ioctl(int fd, abi_long cmd, abi_long arg) + return (ret); + } + ++static inline abi_long ++freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp, ++ abi_ulong guest_envp, int do_fexec) ++{ ++ char **argp, **envp, **qargp, **qarg1; ++ int argc, envc; ++ abi_ulong gp; ++ abi_ulong addr; ++ char **q; ++ int total_size = 0; ++ void *p; ++ abi_long ret; ++ ++ argc = 0; ++ for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { ++ if (get_user_ual(addr, gp)) ++ return (-TARGET_EFAULT); ++ if (!addr) ++ break; ++ argc++; ++ } ++ envc = 0; ++ for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { ++ if (get_user_ual(addr, gp)) ++ return (-TARGET_EFAULT); ++ if (!addr) ++ break; ++ envc++; ++ } ++ ++ qargp = argp = alloca((argc + 3) * sizeof(void *)); ++ /* save the first agrument for the emulator */ ++ *argp++ = (char *)getprogname(); ++ qarg1 = argp; ++ envp = alloca((envc + 1) * sizeof(void *)); ++ for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp)) { ++ ret = -TARGET_EFAULT; ++ goto execve_end; ++ } ++ if (!addr) ++ break; ++ if (!(*q = lock_user_string(addr))) { ++ ret = -TARGET_EFAULT; ++ goto execve_end; ++ } ++ total_size += strlen(*q) + 1; ++ } ++ *q = NULL; ++ ++ for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp)) { ++ ret = -TARGET_EFAULT; ++ goto execve_end; ++ } ++ if (!addr) ++ break; ++ if (!(*q = lock_user_string(addr))) { ++ ret = -TARGET_EFAULT; ++ goto execve_end; ++ } ++ total_size += strlen(*q) + 1; ++ } ++ *q = NULL; ++ ++ /* ++ * This case will not be caught by the host's execve() if its ++ * page size is bigger than the target's. ++ */ ++ if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { ++ ret = -TARGET_E2BIG; ++ goto execve_end; ++ } ++ ++ if (do_fexec) { ++ if (((int)path_or_fd > 0 && ++ is_target_elf_binary((int)path_or_fd)) == 1) { ++ char execpath[PATH_MAX]; ++ ++ /* ++ * The executable is an elf binary for the target ++ * arch. execve() it using the emulator if we can ++ * determine the filename path from the fd. ++ */ ++ if (get_filename_from_fd(getpid(), (int)path_or_fd, ++ execpath, sizeof(execpath)) != NULL) { ++ *qarg1 = execpath; ++ ret = get_errno(execve(qemu_proc_pathname, ++ qargp, envp)); ++ } else { ++ /* Getting the filename path failed. */ ++ ret = -TARGET_EBADF; ++ goto execve_end; ++ } ++ } else { ++ ret = get_errno(fexecve((int)path_or_fd, argp, envp)); ++ } ++ } else { ++ int fd; ++ ++ if (!(p = lock_user_string(path_or_fd))) { ++ ret = -TARGET_EFAULT; ++ goto execve_end; ++ } ++ ++ /* ++ * Check the header and see if it a target elf binary. If so ++ * then execute using qemu user mode emulator. ++ */ ++ fd = open(p, O_RDONLY | O_CLOEXEC); ++ if (fd > 0 && is_target_elf_binary(fd) == 1) { ++ close(fd); ++ /* Execve() as a target binary using emulator. */ ++ *qarg1 = (char *)p; ++ ret = get_errno(execve(qemu_proc_pathname, qargp, envp)); ++ } else { ++ close(fd); ++ /* Execve() as a host native binary. */ ++ ret = get_errno(execve(p, argp, envp)); ++ } ++ unlock_user(p, path_or_fd, 0); ++ } ++ ++execve_end: ++ for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp) || !addr) ++ break; ++ unlock_user(*q, addr, 0); ++ } ++ ++ for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { ++ if (get_user_ual(addr, gp) || !addr) ++ break; ++ unlock_user(*q, addr, 0); ++ } ++ return (ret); ++} ++ ++static inline abi_long ++do_freebsd_execve(abi_ulong path_or_fd, abi_ulong argp, abi_ulong envp) ++{ ++ ++ return (freebsd_exec_common(path_or_fd, argp, envp, 0)); ++} ++ ++static inline abi_long ++do_freebsd_fexecve(abi_ulong path_or_fd, abi_ulong argp, abi_ulong envp) ++{ ++ ++ return (freebsd_exec_common(path_or_fd, argp, envp, 1)); ++} ++ + /* 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_. */ +@@ -4515,96 +5015,14 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + #endif + + case TARGET_FREEBSD_NR_execve: +- { +- char **argp, **envp; +- int argc, envc; +- abi_ulong gp; +- abi_ulong guest_argp; +- abi_ulong guest_envp; +- abi_ulong addr; +- char **q; +- int total_size = 0; +- +- argc = 0; +- guest_argp = arg2; +- for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) { +- if (get_user_ual(addr, gp)) +- goto efault; +- if (!addr) +- break; +- argc++; +- } +- envc = 0; +- guest_envp = arg3; +- for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) { +- if (get_user_ual(addr, gp)) +- goto efault; +- if (!addr) +- break; +- envc++; +- } +- +- argp = alloca((argc + 1) * sizeof(void *)); +- envp = alloca((envc + 1) * sizeof(void *)); +- +- for (gp = guest_argp, q = argp; gp; +- gp += sizeof(abi_ulong), q++) { +- if (get_user_ual(addr, gp)) +- goto execve_efault; +- if (!addr) +- break; +- if (!(*q = lock_user_string(addr))) +- goto execve_efault; +- total_size += strlen(*q) + 1; +- } +- *q = NULL; +- +- for (gp = guest_envp, q = envp; gp; +- gp += sizeof(abi_ulong), q++) { +- if (get_user_ual(addr, gp)) +- goto execve_efault; +- if (!addr) +- break; +- if (!(*q = lock_user_string(addr))) +- goto execve_efault; +- total_size += strlen(*q) + 1; +- } +- *q = NULL; +- +- /* This case will not be caught by the host's execve() if its +- page size is bigger than the target's. */ +- if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) { +- ret = -TARGET_E2BIG; +- goto execve_end; +- } +- if (!(p = lock_user_string(arg1))) +- goto execve_efault; +- ret = get_errno(execve(p, argp, envp)); +- unlock_user(p, arg1, 0); +- +- goto execve_end; +- +- execve_efault: +- ret = -TARGET_EFAULT; ++ ret = do_freebsd_execve(arg1, arg2, arg3); ++ break; + +- execve_end: +- for (gp = guest_argp, q = argp; *q; +- gp += sizeof(abi_ulong), q++) { +- if (get_user_ual(addr, gp) +- || !addr) +- break; +- unlock_user(*q, addr, 0); +- } +- for (gp = guest_envp, q = envp; *q; +- gp += sizeof(abi_ulong), q++) { +- if (get_user_ual(addr, gp) +- || !addr) +- break; +- unlock_user(*q, addr, 0); +- } +- } ++ case TARGET_FREEBSD_NR_fexecve: ++ ret = do_freebsd_fexecve(arg1, arg2, arg3); + break; + ++ + case TARGET_FREEBSD_NR_pipe: + { + int host_pipe[2]; +@@ -5296,11 +5714,11 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + case TARGET_F_SETLKW: + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) + return (-TARGET_EFAULT); +- fl.l_type = tswap16(target_fl->l_type); +- fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapal(target_fl->l_start); + fl.l_len = tswapal(target_fl->l_len); + fl.l_pid = tswap32(target_fl->l_pid); ++ fl.l_type = tswap16(target_fl->l_type); ++ fl.l_whence = tswap16(target_fl->l_whence); + fl.l_sysid = tswap32(target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 0); + ret = get_errno(fcntl(arg1, host_cmd, &fl)); +@@ -5370,13 +5788,16 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + if (reclen > len) + break; + de->d_reclen = tswap16(reclen); ++ de->d_fileno = tswap32(de->d_fileno); + len -= reclen; ++ de = (struct dirent *)((void *)de + reclen); + } + } + unlock_user(dirp, arg2, ret); +- if (arg4) +- if (put_user(nbytes, arg4, abi_ulong)) ++ if (arg4) { ++ if (put_user(basep, arg4, abi_ulong)) + ret = -TARGET_EFAULT; ++ } + } + break; + +@@ -5431,32 +5852,406 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + break; + + +- case TARGET_FREEBSD_NR___acl_get_file: +- case TARGET_FREEBSD_NR___acl_set_file: +- case TARGET_FREEBSD_NR___acl_get_fd: +- case TARGET_FREEBSD_NR___acl_set_fd: +- case TARGET_FREEBSD_NR___acl_delete_file: +- case TARGET_FREEBSD_NR___acl_delete_fd: +- case TARGET_FREEBSD_NR___acl_aclcheck_file: + case TARGET_FREEBSD_NR___acl_aclcheck_fd: ++ { ++ struct acl host_acl; ++ ++ ret = target_to_host_acl(&host_acl, arg3); ++ if (!is_error(ret)) ++ ret = get_errno(__acl_aclcheck_fd(arg1, arg2, ++ &host_acl)); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_aclcheck_file: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = target_to_host_acl(&host_acl, arg3); ++ if (!is_error(ret)) ++ ret = get_errno(__acl_aclcheck_file(path(p) , arg2, ++ &host_acl)); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_aclcheck_link: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = target_to_host_acl(&host_acl, arg3); ++ if (!is_error(ret)) ++ ret = get_errno(__acl_aclcheck_link(path(p), arg2, ++ &host_acl)); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_delete_fd: ++ ret = get_errno(__acl_delete_fd(arg1, arg2)); ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_delete_file: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = get_errno(__acl_delete_file(path(p), arg2)); ++ ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_delete_link: ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = get_errno(__acl_delete_link(path(p), arg2)); ++ ++ unlock_user(p, arg1, 0); ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_get_fd: ++ { ++ struct acl host_acl; ++ ++ ret = get_errno(__acl_get_fd(arg1, arg2, &host_acl)); ++ ++ if (!is_error(ret)) ++ ret = host_to_target_acl(arg3, &host_acl); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_get_file: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = get_errno(__acl_get_file(path(p), arg2, &host_acl)); ++ ++ if (!is_error(ret)) ++ ret = host_to_target_acl(arg3, &host_acl); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR___acl_get_link: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = get_errno(__acl_get_link(path(p), arg2, &host_acl)); ++ ++ if (!is_error(ret)) ++ ret = host_to_target_acl(arg3, &host_acl); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_set_fd: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = target_to_host_acl(&host_acl, arg3); ++ if (!is_error(ret)) ++ ret = get_errno(__acl_set_fd(arg1, arg2, &host_acl)); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ ++ case TARGET_FREEBSD_NR___acl_set_file: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = target_to_host_acl(&host_acl, arg3); ++ if (!is_error(ret)) ++ ret = get_errno(__acl_set_file(path(p), arg2, ++ &host_acl)); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR___acl_set_link: +- case TARGET_FREEBSD_NR___acl_delete_link: +- case TARGET_FREEBSD_NR___acl_aclcheck_link: ++ { ++ struct acl host_acl; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ ret = target_to_host_acl(&host_acl, arg3); ++ if (!is_error(ret)) ++ ret = get_errno(__acl_set_link(path(p), arg2, ++ &host_acl)); ++ ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattrctl: ++ { ++ void *a, *f; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(f = lock_user_string(arg3))) ++ goto efault; ++ if (!(a = lock_user_string(arg5))) ++ goto efault; ++ ++ ret = get_errno(extattrctl(path(p), arg2, f, arg4, a)); ++ ++ unlock_user(a, arg5, 0); ++ unlock_user(f, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_set_file: ++ { ++ void *a, *d; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ if (!(d = lock_user(VERIFY_READ, arg4, arg5, 1))) ++ goto efault; ++ ++ ret = get_errno(extattr_set_file(path(p), arg2, a, d, arg5)); ++ ++ unlock_user(d, arg4, arg5); ++ unlock_user(a, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_get_file: ++ { ++ void *a, *d; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ ++ if (arg4 && arg5 > 0) { ++ if (!(d = lock_user(VERIFY_WRITE, arg4, arg5, 0))) ++ goto efault; ++ ret = get_errno(extattr_get_file(path(p), arg2, a, d, ++ arg5)); ++ unlock_user(d, arg4, arg5); ++ } else { ++ ret = get_errno(extattr_get_file(path(p), arg2, a, ++ NULL, arg5)); ++ } ++ unlock_user(a, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_delete_file: ++ { ++ void *a; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ ++ ret = get_errno(extattr_delete_file(path(p), arg2, a)); ++ ++ unlock_user(a, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_set_fd: ++ { ++ void *a, *d; ++ ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ if (!(d = lock_user(VERIFY_READ, arg4, arg5, 1))) ++ goto efault; ++ ++ ret = get_errno(extattr_set_fd(arg1, arg2, a, d, arg5)); ++ ++ unlock_user(d, arg4, arg5); ++ unlock_user(a, arg3, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_get_fd: ++ { ++ void *a, *d; ++ ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ ++ if (arg4 && arg5 > 0) { ++ if (!(d = lock_user(VERIFY_WRITE, arg4, arg5, 0))) ++ goto efault; ++ ret = get_errno(extattr_get_fd(arg1, arg2, a, d, ++ arg5)); ++ unlock_user(d, arg4, arg5); ++ } else { ++ ret = get_errno(extattr_get_fd(arg1, arg2, a, ++ NULL, arg5)); ++ } ++ unlock_user(a, arg3, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_delete_fd: ++ { ++ void *a; ++ ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ ++ ret = get_errno(extattr_delete_fd(arg1, arg2, a)); ++ ++ unlock_user(a, arg3, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_get_link: ++ { ++ void *a, *d; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ ++ if (arg4 && arg5 > 0) { ++ if (!(d = lock_user(VERIFY_WRITE, arg4, arg5, 0))) ++ goto efault; ++ ret = get_errno(extattr_get_link(path(p), arg2, a, d, ++ arg5)); ++ unlock_user(d, arg4, arg5); ++ } else { ++ ret = get_errno(extattr_get_link(path(p), arg2, a, ++ NULL, arg5)); ++ } ++ unlock_user(a, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_set_link: ++ { ++ void *a, *d; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ if (!(d = lock_user(VERIFY_READ, arg4, arg5, 1))) ++ goto efault; ++ ++ ret = get_errno(extattr_set_link(path(p), arg2, a, d, arg5)); ++ ++ unlock_user(d, arg4, arg5); ++ unlock_user(a, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_delete_link: ++ { ++ void *a; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ if (!(a = lock_user_string(arg3))) ++ goto efault; ++ ++ ret = get_errno(extattr_delete_link(path(p), arg2, a)); ++ ++ unlock_user(a, arg3, 0); ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_list_fd: ++ { ++ void *d; ++ ++ if (arg3 && arg4 > 0) { ++ if (!(d = lock_user(VERIFY_WRITE, arg3, arg4, 0))) ++ goto efault; ++ ret = get_errno(extattr_list_fd(arg1, arg2, d, ++ arg4)); ++ unlock_user(d, arg3, arg4); ++ } else { ++ ret = get_errno(extattr_list_fd(arg1, arg2, ++ NULL, arg4)); ++ } ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_list_file: ++ { ++ void *d; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ if (arg3 && arg4 > 0) { ++ if (!(d = lock_user(VERIFY_WRITE, arg3, arg4, 0))) ++ goto efault; ++ ret = get_errno(extattr_list_file(path(p), arg2, d, ++ arg4)); ++ unlock_user(d, arg3, arg4); ++ } else { ++ ret = get_errno(extattr_list_file(path(p), arg2, ++ NULL, arg4)); ++ } ++ unlock_user(p, arg1, 0); ++ } ++ break; ++ + case TARGET_FREEBSD_NR_extattr_list_link: +- ret = unimplemented(num); ++ { ++ void *d; ++ ++ if (!(p = lock_user_string(arg1))) ++ goto efault; ++ ++ if (arg3 && arg4 > 0) { ++ if (!(d = lock_user(VERIFY_WRITE, arg3, arg4, 0))) ++ goto efault; ++ ret = get_errno(extattr_list_link(path(p), arg2, d, ++ arg4)); ++ unlock_user(d, arg3, arg4); ++ } else { ++ ret = get_errno(extattr_list_link(path(p), arg2, ++ NULL, arg4)); ++ } ++ ++ unlock_user(p, arg1, 0); ++ } + break; + + case TARGET_FREEBSD_NR_setlogin: +@@ -5635,6 +6430,10 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4); + break; + ++ case TARGET_FREEBSD_NR_freebsd7___semctl: ++ ret = unimplemented(num); ++ break; ++ + case TARGET_FREEBSD_NR_msgctl: + ret = do_msgctl(arg1, arg2, arg3); + break; +@@ -5715,7 +6514,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + break; + + case TARGET_FREEBSD_NR_seteuid: +- ret = get_errno(setegid(arg1)); ++ ret = get_errno(seteuid(arg1)); + break; + + case TARGET_FREEBSD_NR_getpgrp: +@@ -6953,7 +7752,7 @@ void syscall_init(void) + + #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__ ++#if defined(__FreeBSD__) + #include "freebsd/syscall_types.h" + #else + #warning No syscall_types.h +diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h +index 3eb760b..8a92403 100644 +--- a/bsd-user/syscall_defs.h ++++ b/bsd-user/syscall_defs.h +@@ -203,12 +203,12 @@ struct target_pollfd { + #include "openbsd/syscall_nr.h" + + struct target_flock { +- unsigned long long l_start; +- unsigned long long l_len; +- int l_pid; +- int l_sysid; +- short l_type; +- short l_whence; ++ abi_long l_start; ++ abi_long l_len; ++ int32_t l_pid; ++ int16_t l_type; ++ int16_t l_whence; ++ int32_t l_sysid; + } QEMU_PACKED; + + struct target_iovec { +@@ -451,6 +451,7 @@ typedef struct target_siginfo { + int32_t si_code; /* signal code */ + int32_t si_pid; /* sending process */ + int32_t si_uid; /* sender's ruid */ ++ int32_t si_status; /* exit value */ + abi_ulong si_addr; /* faulting instruction */ + + union target_sigval si_value; /* signal value */ +@@ -756,3 +757,41 @@ struct target_timex { + struct target_sched_param { + int32_t sched_priority; + }; ++ ++ ++/* ++ * sys/acl.h ++ */ ++ ++#define TARGET_ACL_MAX_ENTRIES 254 ++ ++struct target_acl_entry { ++ int32_t ae_tag; ++ uint32_t ae_id; ++ uint16_t ae_perm; ++ uint16_t ae_entry_type; ++ uint16_t ae_flags; ++}; ++ ++struct target_acl { ++ uint32_t acl_maxcnt; ++ uint32_t acl_cnt; ++ int32_t acl_space[4]; ++ struct target_acl_entry acl_entry[TARGET_ACL_MAX_ENTRIES]; ++}; ++ ++ ++/* ++ * netinet/in.h ++ */ ++ ++struct target_ip_mreq { ++ struct target_in_addr imr_multiaddr; ++ struct target_in_addr imr_interface; ++}; ++ ++struct target_ip_mreqn { ++ struct target_in_addr imr_multiaddr; ++ struct target_in_addr imr_address; ++ int32_t imr_ifindex; ++}; +diff --git a/configure b/configure +index d99584d..6d17c97 100755 +--- a/configure ++++ b/configure +@@ -434,8 +434,9 @@ FreeBSD) + make="${MAKE-gmake}" + audio_drv_list="oss" + audio_possible_drivers="oss sdl esd pa" +- # needed for kinfo_getvmmap(3) in libutil.h +- LIBS="-lutil $LIBS" ++ # -lutil needed for kinfo_getvmmap(3) in libutil.h ++ # -lprocstat needed for procstat_*(3) in main.c ++ LIBS="-lprocstat -lutil $LIBS" + ;; + DragonFly) + bsd="yes" +@@ -1237,6 +1238,11 @@ if test "$static" = "yes" ; then + else + pie="no" + fi ++ if test "$bsd" = "yes" ; then ++ # Missing libs when linking statically ++ LIBS="$LIBS -lintl -lkvm" ++ libs_qga="-lintl $libs_qga" ++ fi + fi + + if test "$pie" = ""; then +diff --git a/util/aes.c b/util/aes.c +index 1da7bff..30a6608 100644 +--- a/util/aes.c ++++ b/util/aes.c +@@ -877,6 +877,7 @@ int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + return 0; + } + ++#if defined(CONFIG_STATIC) && ! defined(__FreeBSD__) + #ifndef AES_ASM + /* + * Encrypt a single block +@@ -1312,3 +1313,4 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + } + } + } ++#endif /* CONFIG_STATIC && ! __FreeBSD__ */ Index: files/patch-z9d-bsd-user-sson003d @@ -0,0 +1,92 @@ +diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c +index 8abb1dd..c2c3a65 100644 +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -798,6 +798,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + p -= roundup(execpath_len, sizeof(abi_ulong)); + /* XXX - check return value of memcpy_to_target() */ + memcpy_to_target(p, execpath, execpath_len); ++ strlcpy(target_proc_pathname, execpath, execpath_len); + } + + /* Add canary for SSP. */ +diff --git a/bsd-user/main.c b/bsd-user/main.c +index bb614de..b6aaa7e 100644 +--- a/bsd-user/main.c ++++ b/bsd-user/main.c +@@ -62,6 +62,7 @@ unsigned long x86_stack_size = 512 * 1024; + + static void save_proc_pathname(void); + char qemu_proc_pathname[PATH_MAX]; ++char target_proc_pathname[PATH_MAX]; + + #ifdef __FreeBSD__ + static void +diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h +index 110b54e..d51f50c 100644 +--- a/bsd-user/qemu.h ++++ b/bsd-user/qemu.h +@@ -224,6 +224,7 @@ void mmap_fork_end(int child); + /* main.c */ + extern unsigned long x86_stack_size; + extern char qemu_proc_pathname[]; ++extern char target_proc_pathname[]; + + /* user access */ + +diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c +index 74b5c86..636083a 100644 +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -485,8 +485,6 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol + abi_ulong oldlen = 0; + int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; + uint32_t kind = 0; +- abi_ulong argv, argv0; +- char *fullpath = NULL; + + if (oldlenp) + if (get_user_ual(oldlen, oldlenp)) +@@ -533,30 +531,14 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol + case KERN_PROC: + switch(snamep[2]) { + case KERN_PROC_PATHNAME: +- if (get_user_ual(argv, TARGET_PS_STRINGS)) { +- ret = -TARGET_EFAULT; +- goto out; +- } +- if (get_user_ual(argv0, argv)) { +- ret = -TARGET_EFAULT; +- goto out; +- } +- +- fullpath = realpath(g2h(argv0), NULL); +- if (NULL == fullpath) +- fullpath = (char *)g2h(argv0); +- holdlen = strlen(fullpath) + 1; ++ holdlen = strlen(target_proc_pathname) + 1; + if (holdp) { + if (oldlen < holdlen) { + ret = -TARGET_EINVAL; + goto out; + } +- if (!access_ok(VERIFY_WRITE, argv0, +- holdlen)) { +- ret = -TARGET_EFAULT; +- goto out; +- } +- strlcpy(holdp, fullpath, oldlen); ++ strlcpy(holdp, target_proc_pathname, ++ oldlen); + } + ret = 0; + goto out; +@@ -597,8 +579,6 @@ static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong ol + #endif + + out: +- if (fullpath) +- free(fullpath); + if (oldlenp) + put_user_ual(holdlen, oldlenp); + unlock_user(hnamep, namep, 0); Index: files/patch-z9e-bsd-user-cognet-elfload @@ -0,0 +1,15 @@ +diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c +index 8abb1dd..eee159b 100644 +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -999,9 +999,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); ++#ifndef __FreeBSD__ + NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); +-#ifndef __FreeBSD__ + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, u_platform); + #endif Index: files/patch-z9f-bsd-user-sson003f @@ -0,0 +1,321 @@ +diff --git a/bsd-user/arm/target_signal.h b/bsd-user/arm/target_signal.h +index 6b7bb67..4a9e518 100644 +--- a/bsd-user/arm/target_signal.h ++++ b/bsd-user/arm/target_signal.h +@@ -3,15 +3,57 @@ + + #include "cpu.h" + +-static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) +-{ +- return state->regs[13]; +-} ++#define TARGET_REG_R0 0 ++#define TARGET_REG_R1 1 ++#define TARGET_REG_R2 2 ++#define TARGET_REG_R3 3 ++#define TARGET_REG_R4 4 ++#define TARGET_REG_R5 5 ++#define TARGET_REG_R6 6 ++#define TARGET_REG_R7 7 ++#define TARGET_REG_R8 8 ++#define TARGET_REG_R9 9 ++#define TARGET_REG_R10 10 ++#define TARGET_REG_R11 11 ++#define TARGET_REG_R12 12 ++#define TARGET_REG_R13 13 ++#define TARGET_REG_R14 14 ++#define TARGET_REG_R15 15 ++#define TARGET_REG_CPSR 16 ++/* Convenience synonyms */ ++#define TARGET_REG_FP TARGET_REG_R11 ++#define TARGET_REG_SP TARGET_REG_R13 ++#define TARGET_REG_LR TARGET_REG_R14 ++#define TARGET_REG_PC TARGET_REG_R15 ++ ++#define TARGET_GET_MC_CLEAR_RET 1 + + #define TARGET_MINSIGSTKSZ (1024 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) ++#define TARGET__NGREG 17 ++ ++typedef struct { ++ uint32_t __fp_fpsr; ++ struct { ++ uint32_t __fp_exponent; ++ uint32_t __fp_mantissa_hi; ++ uint32_t __fp_mantissa_lo; ++ } __fp_fr[8]; ++} target__fpregset_t; + +-typedef target_ulong target_mcontext_t; /* dummy */ ++typedef struct { ++ uint32_t __vfp_fpscr; ++ uint32_t __vfp_fstmx[33]; ++ uint32_t __vfp_fpsid; ++} target__vfpregset_t; ++ ++typedef struct { ++ uint32_t __gregs[TARGET__NGREG]; ++ union { ++ target__fpregset_t __fpregs; ++ target__vfpregset_t __vfpregs; ++ } __fpu; ++} target_mcontext_t; + + typedef struct target_ucontext { + target_sigset_t uc_sigmask; +@@ -22,18 +64,119 @@ typedef struct target_ucontext { + int32_t __spare__[4]; + } target_ucontext_t; + ++struct target_sigframe { ++ target_siginfo_t sf_si; /* saved siginfo */ ++ target_ucontext_t sf_uc; /* saved ucontext */ ++}; ++ ++#define TARGET_SZSIGCODE (8 * 4) ++ ++/* Compare to arm/arm/locore.S ENTRY_NP(sigcode) */ ++static inline int ++install_sigtramp(abi_ulong offset, unsigned sigf_us, uint32_t sys_sigreturn) ++{ ++ int i; ++ uint32_t sys_exit = TARGET_FREEBSD_NR_exit; ++ /* ++ * The code has to load r7 manually rather than using ++ * "ldr r7, =SYS_return to make sure the size of the ++ * code is correct. ++ */ ++ uint32_t sigtramp_code[] = { ++ /* 1 */ 0xE1A0000D, /* mov r0, sp */ ++ /* 2 */ 0xE59F700C, /* ldr r7, [pc, #12] */ ++ /* 3 */ 0xEF000000 + sys_sigreturn, /* swi (SYS_sigreturn) */ ++ /* 4 */ 0xE59F7008, /* ldr r7, [pc, #8] */ ++ /* 5 */ 0xEF000000 + sys_exit, /* swi (SYS_exit)*/ ++ /* 6 */ 0xEAFFFFFA, /* b . -16 */ ++ /* 7 */ sys_sigreturn, ++ /* 8 */ sys_exit ++ }; ++ ++ for(i = 0; i < 8; i++) ++ tswap32s(&sigtramp_code[i]); ++ ++ return(memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE)); ++} ++ ++static inline abi_ulong ++get_sp_from_cpustate(CPUARMState *state) ++{ ++ return state->regs[13]; /* sp */ ++} ++ ++/* ++ * Compare to arm/arm/machdep.c sendsig() ++ * Assumes that the target stack frame memory is locked. ++ */ ++static inline int ++set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame, ++ abi_ulong frame_addr, struct target_sigaction *ka) ++{ ++ /* ++ * Arguments to signal handler: ++ * r0 = signal number ++ * r1 = siginfo pointer ++ * r2 = ucontext pointer ++ * r5 = ucontext pointer ++ * pc = signal handler pointer ++ * sp = sigframe struct pointer ++ * lr = sigtramp at base of user stack ++ */ ++ ++ regs->regs[0] = sig; ++ regs->regs[1] = frame_addr + ++ offsetof(struct target_sigframe, sf_si); ++ regs->regs[2] = frame_addr + ++ offsetof(struct target_sigframe, sf_uc); ++ ++ /* the trampoline uses r5 as the uc address */ ++ regs->regs[5] = frame_addr + ++ offsetof(struct target_sigframe, sf_uc); ++ regs->regs[TARGET_REG_PC] = ka->_sa_handler; ++ regs->regs[TARGET_REG_SP] = frame_addr; ++ regs->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; ++ ++ return (0); ++} ++ ++/* Compare to arm/arm/machdep.c get_mcontext() */ + static inline int +-get_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++get_mcontext(CPUARMState *regs, target_mcontext_t *mcp, int clear_ret) + { +- fprintf(stderr, "ARM doesn't have support for get_mcontext()\n"); +- return (-TARGET_ENOSYS); ++ int i, err = 0; ++ uint32_t *gr = mcp->__gregs; ++ ++ ++ if (clear_ret & TARGET_GET_MC_CLEAR_RET) ++ gr[TARGET_REG_R0] = 0; ++ else ++ gr[TARGET_REG_R0] = tswap32(regs->regs[0]); ++ for(i = 1; i < 12; i++) ++ gr[i] = tswap32(regs->regs[i]); ++ gr[TARGET_REG_SP] = tswap32(regs->regs[13]); ++ gr[TARGET_REG_LR] = tswap32(regs->regs[14]); ++ gr[TARGET_REG_PC] = tswap32(regs->regs[15]); ++ gr[TARGET_REG_CPSR] = tswap32(regs->spsr); ++ ++ return (err); + } + ++/* Compare to arm/arm/machdep.c set_mcontext() */ + static inline int +-set_mcontext(CPUArchState *regs, target_mcontext_t *mcp, int flags) ++set_mcontext(CPUARMState *regs, target_mcontext_t *mcp, int flags) + { +- fprintf(stderr, "ARM doesn't have support for set_mcontext()\n"); +- return (-TARGET_ENOSYS); ++ int i, err = 0; ++ const uint32_t *gr = mcp->__gregs; ++ ++ for(i = 0; i < 12; i++) ++ regs->regs[i] = tswap32(gr[i]); ++ regs->regs[13] = tswap32(gr[TARGET_REG_SP]); ++ regs->regs[14] = tswap32(gr[TARGET_REG_LR]); ++ regs->regs[15] = tswap32(gr[TARGET_REG_PC]); ++ regs->spsr = tswap32(gr[TARGET_REG_CPSR]); ++ ++ return (err); + } + + #endif /* TARGET_SIGNAL_H */ +diff --git a/bsd-user/arm/target_vmparam.h b/bsd-user/arm/target_vmparam.h +index 24dca00..bc50fbb 100644 +--- a/bsd-user/arm/target_vmparam.h ++++ b/bsd-user/arm/target_vmparam.h +@@ -18,8 +18,6 @@ struct target_ps_strings { + + #define TARGET_PS_STRINGS (TARGET_USRSTACK - sizeof(struct target_ps_strings)) + +-#define TARGET_SZSIGCODE 0 +- + /* Make stack size large enough to hold everything. */ + #define TARGET_STACK_SIZE ((x86_stack_size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) ? \ + MAX_ARG_PAGES*TARGET_PAGE_SIZE : x86_stack_size) +diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c +index c2c3a65..76681e1 100644 +--- a/bsd-user/elfload.c ++++ b/bsd-user/elfload.c +@@ -690,24 +690,6 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, + return p; + } + +-#if defined(TARGET_MIPS64) +-static inline int +-install_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned syscall) +-{ +- int i; +- uint32_t sigtramp_code[] = { +- 0x67A40000 + sigf_uc, /* daddu $a0, $sp, (sigf_uc) */ +- 0x24020000 + syscall, /* li $v0, (syscall) */ +- 0x0000000C, /* syscall */ +- 0x0000000D /* break */ +- }; +- +- for(i = 0; i < 4; i++) +- tswap32s(&sigtramp_code[i]); +- +- return (memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE)); +-} +-#endif + + static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, + struct image_info *info) +diff --git a/bsd-user/mips64/target_signal.h b/bsd-user/mips64/target_signal.h +index c592136..f657909 100644 +--- a/bsd-user/mips64/target_signal.h ++++ b/bsd-user/mips64/target_signal.h +@@ -5,7 +5,6 @@ + + #define TARGET_MINSIGSTKSZ (512 * 4) + #define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) +-#define TARGET_SZSIGCODE 16 + + struct target_sigcontext { + target_sigset_t sc_mask; /* signal mask to retstore */ +@@ -56,9 +55,29 @@ get_sp_from_cpustate(CPUMIPSState *state) + return state->active_tc.gpr[29]; + } + ++#define TARGET_SZSIGCODE (4 * 4) ++ ++/* Compare to mips/mips/locore.S sigcode() */ ++static inline int ++install_sigtramp(abi_ulong offset, unsigned sigf_uc, unsigned sys_sigreturn) ++{ ++ int i; ++ uint32_t sigtramp_code[] = { ++ /* 1 */ 0x67A40000 + sigf_uc, /* daddu $a0, $sp, (sigf_uc) */ ++ /* 2 */ 0x24020000 + sys_sigreturn, /* li $v0, (sys_sigreturn) */ ++ /* 3 */ 0x0000000C, /* syscall */ ++ /* 4 */ 0x0000000D /* break */ ++ }; ++ ++ for(i = 0; i < 4; i++) ++ tswap32s(&sigtramp_code[i]); ++ ++ return (memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE)); ++} ++ + /* + * Compare to mips/mips/pm_machdep.c sendsig() +- * Assumes that "frame" memory is locked. ++ * Assumes that target stack frame memory is locked. + */ + static inline int + set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, +@@ -67,6 +86,11 @@ set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, + + /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */ + ++ /* MIPS only struct target_sigframe members: */ ++ frame->sf_signum = sig; ++ frame->sf_siginfo = (abi_ulong)&frame->sf_si; ++ frame->sf_ucontext = (abi_ulong)&frame->sf_uc; ++ + /* + * Arguments to signal handler: + * a0 ($4) = signal number +diff --git a/bsd-user/signal.c b/bsd-user/signal.c +index 29e8e12..b04e874 100644 +--- a/bsd-user/signal.c ++++ b/bsd-user/signal.c +@@ -613,7 +613,7 @@ do_sigaction(int sig, const struct target_sigaction *act, + return (ret); + } + +-#if defined(TARGET_MIPS64) /* || defined(TARGET_SPARC64) */ ++#if defined(TARGET_MIPS64) || defined(TARGET_ARM) + + static inline abi_ulong + get_sigframe(struct target_sigaction *ka, CPUArchState *regs, size_t frame_size) +@@ -715,17 +715,8 @@ static void setup_frame(int sig, int code, struct target_sigaction *ka, + } + #endif + +- frame->sf_signum = sig; +- frame->sf_siginfo = (abi_ulong)&frame->sf_si; +- frame->sf_ucontext = (abi_ulong)&frame->sf_uc; +- +- } else { +- frame->sf_signum = sig; +- frame->sf_siginfo = 0; +- frame->sf_ucontext = 0; + } + +- + if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) + goto give_sigsegv; + Index: files/patch-za-bsd-user-8fix @@ -0,0 +1,28 @@ +--- a/bsd-user/syscall.c ++++ b/bsd-user/syscall.c +@@ -123,6 +123,7 @@ get_filename_from_fd(pid_t pid, int fd, + struct filestat *fst; + char *ret = NULL; + ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + procstat = procstat_open_sysctl(); + if (NULL == procstat) + goto out; +@@ -152,6 +153,7 @@ out: + procstat_freeprocs(procstat, kipp); + if (procstat != NULL) + procstat_close(procstat); ++#endif + return (ret); + } + +@@ -1739,7 +1741,9 @@ int_case: + case IP_RECVDSTADDR: + + case IP_RETOPTS: ++#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 + case IP_RECVTOS: ++#endif + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + case IP_PORTRANGE: