Merge branch 'net80211-update' of git://leaf.dragonflybsd.org/~rpaulo/dragonfly into...
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 18 Mar 2010 21:18:36 +0000 (14:18 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 18 Mar 2010 21:18:36 +0000 (14:18 -0700)
125 files changed:
Makefile_upgrade.inc
bin/cpdup/Makefile
contrib/groff/tmac/doc-common
gnu/usr.bin/cc44/gmp/Makefile
gnu/usr.bin/groff/tmac/mdoc.local
gnu/usr.bin/groff/tmac/patches/doc-syms.no_obj.patch [deleted file]
lib/libdevstat/devstat.c
lib/libdevstat/devstat.h
lib/librt/mq_receive.2
sbin/hammer/hammer.8
share/man/man4/Makefile
share/man/man4/isa.4
share/man/man4/lm.4
share/man/man4/wbsio.4 [new file with mode: 0644]
share/man/man9/Makefile
share/man/man9/fetch.9
share/man/man9/nlookup.9
share/man/man9/taskqueue.9
share/zoneinfo/asia
share/zoneinfo/australasia
share/zoneinfo/southamerica
sys/bus/pci/pci.c
sys/conf/files
sys/config/GENERIC
sys/config/LINT
sys/config/X86_64_GENERIC
sys/dev/disk/ahci/ahci.c
sys/dev/disk/ahci/ahci.h
sys/dev/disk/ahci/ahci_dragonfly.c
sys/dev/disk/ahci/ahci_pm.c
sys/dev/netif/e1000/if_em.c
sys/dev/netif/e1000/if_igb.c
sys/dev/netif/e1000/ifcap_defines.h [new file with mode: 0644]
sys/dev/powermng/wbsio/Makefile [new file with mode: 0644]
sys/dev/powermng/wbsio/wbsio.c [new file with mode: 0644]
sys/emulation/linux/Makefile
sys/emulation/linux/i386/linprocfs/linprocfs.h
sys/emulation/linux/i386/linprocfs/linprocfs_misc.c
sys/emulation/linux/i386/linprocfs/linprocfs_subr.c
sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c
sys/emulation/linux/i386/linux.h
sys/emulation/linux/i386/linux_dummy.c
sys/emulation/linux/i386/linux_genassym.c
sys/emulation/linux/i386/linux_locore.s
sys/emulation/linux/i386/linux_machdep.c
sys/emulation/linux/i386/linux_proto.h
sys/emulation/linux/i386/linux_support.s [new file with mode: 0644]
sys/emulation/linux/i386/linux_syscall.h
sys/emulation/linux/i386/linux_sysent.c
sys/emulation/linux/i386/linux_sysvec.c
sys/emulation/linux/i386/linux_union.h
sys/emulation/linux/i386/syscalls.master
sys/emulation/linux/linux_emuldata.c [new file with mode: 0644]
sys/emulation/linux/linux_emuldata.h [new file with mode: 0644]
sys/emulation/linux/linux_epoll.c [new file with mode: 0644]
sys/emulation/linux/linux_epoll.h [new file with mode: 0644]
sys/emulation/linux/linux_file.c
sys/emulation/linux/linux_futex.c [new file with mode: 0644]
sys/emulation/linux/linux_futex.h [new file with mode: 0644]
sys/emulation/linux/linux_ioctl.c
sys/emulation/linux/linux_ioctl.h
sys/emulation/linux/linux_ipc.c
sys/emulation/linux/linux_ipc.h
sys/emulation/linux/linux_mib.c
sys/emulation/linux/linux_misc.c
sys/emulation/linux/linux_signal.c
sys/emulation/linux/linux_socket.c
sys/emulation/linux/linux_socket.h
sys/emulation/linux/linux_stats.c
sys/emulation/linux/linux_time.c [new file with mode: 0644]
sys/emulation/linux/linux_util.c
sys/kern/imgact_elf.c
sys/kern/kern_checkpoint.c
sys/kern/kern_event.c
sys/kern/kern_exec.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/kern_msfbuf.c [deleted file]
sys/kern/kern_synch.c
sys/kern/kern_time.c
sys/kern/subr_disk.c
sys/kern/subr_diskslice.c
sys/kern/sysv_sem.c
sys/kern/sysv_shm.c
sys/kern/uipc_syscalls.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_synth.c
sys/net/if.h
sys/platform/pc32/conf/files
sys/platform/pc32/i386/pmap.c
sys/platform/pc32/i386/support.s
sys/platform/pc32/i386/trap.c
sys/sys/event.h
sys/sys/eventhandler.h
sys/sys/msfbuf.h [deleted file]
sys/sys/nchstats.h
sys/sys/nlookup.h
sys/sys/proc.h
sys/sys/sem.h
sys/sys/systm.h
sys/sys/thread.h
sys/vfs/gnu/ext2fs/ext2_lookup.c
sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_btree.c
sys/vfs/hammer/hammer_cursor.c
sys/vfs/hammer/hammer_cursor.h
sys/vfs/hammer/hammer_flusher.c
sys/vfs/hammer/hammer_inode.c
sys/vfs/hammer/hammer_io.c
sys/vfs/hammer/hammer_object.c
sys/vfs/hammer/hammer_ondisk.c
sys/vfs/hammer/hammer_recover.c
sys/vfs/hammer/hammer_subs.c
sys/vfs/isofs/cd9660/cd9660_lookup.c
sys/vfs/nfs/nfs_bio.c
sys/vfs/procfs/procfs_map.c
sys/vfs/procfs/procfs_vnops.c
sys/vfs/udf/udf_vnops.c
sys/vfs/ufs/ufs_lookup.c
sys/vm/vm_page.h
usr.bin/fstat/fstat.c
usr.bin/systat/vmstat.c
usr.bin/vmstat/vmstat.c
usr.sbin/mptable/Makefile
usr.sbin/mptable/mptable.c

index b0b7c35..2ec0914 100644 (file)
@@ -1198,3 +1198,4 @@ TO_REMOVE+=/usr/share/games/fortune/fortunes2-o.dat
 TO_REMOVE+=/usr/share/games/fortune/fortunes2.dat
 TO_REMOVE+=/usr/share/man/cat8/tmpfs.8.gz
 TO_REMOVE+=/usr/share/man/man8/tmpfs.8.gz
+TO_REMOVE+=/usr/include/sys/msfbuf.h
index 9675d30..723edac 100644 (file)
@@ -8,8 +8,6 @@ SRCS=   cpdup.c hcproto.c hclink.c misc.c fsmid.c
 CFLAGS += -D_ST_FLAGS_PRESENT_=1
 .endif
 
-WARNS?=        6
-
 .if !defined(NOMD5)
 SRCS+= md5.c
 .endif
index 8b1afa5..d36a47e 100644 (file)
@@ -77,6 +77,7 @@
 .nr Dq 12n
 .nr Ds 6n\" many manpages still use this as a -width value
 .nr Dv 12n
+.nr Dx 1
 .nr Ec 3
 .nr Ef 8n\" ?
 .nr Ek 8n\" ?
index 6ab4f39..ce279da 100644 (file)
@@ -181,9 +181,10 @@ LO_OBJECTS=        ${MPF_OBJECTS} ${MPZ_OBJECTS} ${MPQ_OBJECTS} ${MPN_OBJECTS} \
 .if exists(${mapsource}) && empty(MPNSRC:M${source})
 
 .if !exists(${source})
-${source}: ${mapsource}
-       cp ${.ALLSRC} ${.TARGET}
+${source}: ${mapsource} mkdirs
+       cp ${.ALLSRC:Nmkdirs} ${.TARGET}
 CLEANFILES+=   ${source}
+.ORDER: mkdir ${source}
 .endif
 
 MPNSRC+=       ${source}
index b6c7416..e950a8e 100644 (file)
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD: src/gnu/usr.bin/groff/tmac/mdoc.local,v 1.2.2.19 2003/03/25 10:20:12 murray Exp $
-.\" $DragonFly: src/gnu/usr.bin/groff/tmac/mdoc.local,v 1.27 2008/09/30 13:26:17 swildner Exp $
 .\"
 .\"     %beginstrip%
 .
-.\" Macro identifier for the DragonFly OS.
-.nr Dx 1
-.
-.
 .eo
 .
 .
 .ds doc-str-Lb-libvgl           Video Graphics Library (libvgl, \-lvgl)
 .
 .
-.\" Standards names not in groff.
-.ds doc-str-St--isoC-amd1       \*[doc-Tn-font-size]ISO/IEC\*[doc-str-St] 9899/AMD1:1995
-.as doc-str-St--isoC-amd1       " (\*[Lq]\*[doc-Tn-font-size]ISO\~C\^90\*[doc-str-St], Amendment 1\*[Rq])
-.ds doc-str-St--isoC-tcor1      \*[doc-Tn-font-size]ISO/IEC\*[doc-str-St] 9899/TCOR1:1994
-.as doc-str-St--isoC-tcor1      " (\*[Lq]\*[doc-Tn-font-size]ISO\~C\^90\*[doc-str-St], Technical Corrigendum 1\*[Rq])
-.ds doc-str-St--isoC-tcor2      \*[doc-Tn-font-size]ISO/IEC\*[doc-str-St] 9899/TCOR2:1995
-.as doc-str-St--isoC-tcor2      " (\*[Lq]\*[doc-Tn-font-size]ISO\~C\^90\*[doc-str-St], Technical Corrigendum 2\*[Rq])
-.ds doc-str-St--ieee1275-94     \*[doc-Tn-font-size]\%IEEE\*[doc-str-St] Std 1275-1994
-.as doc-str-St--ieee1275-94     " (\*[Lq]\*[doc-Tn-font-size]Open Firmware\*[doc-str-St]\*[Rq])
-.ds doc-str-St--susv3           Version\~3 of the Single \*[doc-Tn-font-size]UNIX\*[doc-str-St] Specification
-.as doc-str-St--susv3           " (\*[Lq]\*[doc-Tn-font-size]SUSv3\*[doc-str-St]\*[Rq])
-.
-.
 .\" Default .Os value
 .ds doc-default-operating-system DragonFly\~2.5
 .
 .
 .\" DragonFly releases not found in doc-common
-.ds doc-operating-system-DragonFly-1.0 1.0
-.ds doc-operating-system-DragonFly-1.1 1.1
-.ds doc-operating-system-DragonFly-1.2 1.2
-.ds doc-operating-system-DragonFly-1.3 1.3
-.ds doc-operating-system-DragonFly-1.4 1.4
-.ds doc-operating-system-DragonFly-1.5 1.5
-.ds doc-operating-system-DragonFly-1.6 1.6
 .ds doc-operating-system-DragonFly-1.7 1.7
-.ds doc-operating-system-DragonFly-1.8 1.8
 .ds doc-operating-system-DragonFly-1.9 1.9
-.ds doc-operating-system-DragonFly-1.10 1.10
 .ds doc-operating-system-DragonFly-1.11 1.11
-.ds doc-operating-system-DragonFly-1.12 1.12
 .ds doc-operating-system-DragonFly-1.13 1.13
-.ds doc-operating-system-DragonFly-2.0 2.0
 .ds doc-operating-system-DragonFly-2.1 2.1
 .ds doc-operating-system-DragonFly-2.2 2.2
 .ds doc-operating-system-DragonFly-2.3 2.3
 .ds doc-operating-system-DragonFly-2.5 2.5
 .
 .\" FreeBSD releases not found in doc-common.
-.ds doc-operating-system-FreeBSD-4.11 4.11
-.ds doc-operating-system-FreeBSD-5.4  5.4
-.ds doc-operating-system-FreeBSD-5.5  5.5
-.ds doc-operating-system-FreeBSD-6.0  6.0
-.ds doc-operating-system-FreeBSD-6.1  6.1
-.ds doc-operating-system-FreeBSD-6.3  6.3
-.ds doc-operating-system-FreeBSD-7.0  7.0
-.ds doc-operating-system-FreeBSD-7.1  7.1
 .ds doc-operating-system-FreeBSD-8.0  8.0
 .
 .\" NetBSD releases not found in doc-common.
-.ds doc-operating-system-NetBSD-1.6.3 1.6.3
-.ds doc-operating-system-NetBSD-3.0   3.0
-.ds doc-operating-system-NetBSD-4.0   4.0
 .ds doc-operating-system-NetBSD-5.0   5.0
+.ds doc-operating-system-NetBSD-6.0   6.0
 .
 .\" Definitions not (yet) in doc-syms
 .ds doc-str-St--p1003.1-2008   \*[doc-Tn-font-size]\%IEEE\*[doc-str-St] Std 1003.1-2008
diff --git a/gnu/usr.bin/groff/tmac/patches/doc-syms.no_obj.patch b/gnu/usr.bin/groff/tmac/patches/doc-syms.no_obj.patch
deleted file mode 100644 (file)
index 564373c..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-$DragonFly: src/gnu/usr.bin/groff/tmac/patches/doc-syms.no_obj.patch,v 1.1 2005/09/08 10:58:16 asmodai Exp $
-
---- doc-syms   2005-09-08 12:50:26.000000000 +0200
-+++ doc-syms   2005-09-08 12:52:04.000000000 +0200
-@@ -324,6 +262,70 @@
- ..
- .
- .
-+.\" NS Dx user macro
-+.\" NS   print DragonFly
-+.\" NS
-+.\" NS modifies:
-+.\" NS   doc-arg-ptr
-+.\" NS   doc-curr-font
-+.\" NS   doc-curr-size
-+.\" NS   doc-macro-name
-+.\" NS
-+.\" NS local variable:
-+.\" NS   doc-str-Dx
-+.\" NS   doc-str-Dx1
-+.\" NS
-+.\" NS width register `Dx' defined in doc-common
-+.
-+.\" we use the doc-operating-system-DragonFly-* strings defined in doc-common
-+.
-+.de Dx
-+.  nr doc-curr-font \n[.f]
-+.  nr doc-curr-size \n[.ps]
-+.  ds doc-str-Dx \f[\n[doc-curr-font]]\s[\n[doc-curr-size]u]
-+.
-+.  \" default value if no argument
-+.  ds doc-str-Dx1 \*[doc-Tn-font-size]\%DragonFly\*[doc-str-Dx]
-+.
-+.  if !\n[doc-arg-limit] \
-+.    if \n[.$] \{\
-+.      ds doc-macro-name Dx
-+.      doc-parse-args \$@
-+.    \}
-+.
-+.  if (\n[doc-arg-limit] > \n[doc-arg-ptr]) \{\
-+.    nr doc-arg-ptr +1
-+.    ie (\n[doc-type\n[doc-arg-ptr]] == 2) \{\
-+.      ie \A\a\*[doc-arg\n[doc-arg-ptr]]\a \{\
-+.        ie d doc-operating-system-DragonFly-\*[doc-arg\n[doc-arg-ptr]] \
-+.          as doc-str-Dx1 \~\*[doc-operating-system-DragonFly-\*[doc-arg\n[doc-arg-ptr]]]
-+.        el \{\
-+.          tmc mdoc warning: .Dx: Unknown DragonFly version
-+.          tm1 " `\*[doc-arg\n[doc-arg-ptr]]' (#\n[.c])
-+.          as doc-str-Dx1 \~\*[doc-arg\n[doc-arg-ptr]]
-+.      \}\}
-+.      el \
-+.        as doc-str-Dx1 \~\*[doc-arg\n[doc-arg-ptr]]
-+.    \}
-+.    el \
-+.      nr doc-arg-ptr -1
-+.  \}
-+.
-+.  \" replace current argument with result
-+.  ds doc-arg\n[doc-arg-ptr] "\*[doc-str-Dx1]
-+.  nr doc-type\n[doc-arg-ptr] 2
-+.  ds doc-space\n[doc-arg-ptr] "\*[doc-space]
-+.
-+.  \" recompute space vector for remaining arguments
-+.  nr doc-num-args (\n[doc-arg-limit] - \n[doc-arg-ptr])
-+.  nr doc-arg-limit \n[doc-arg-ptr]
-+.  if \n[doc-num-args] \
-+.    doc-parse-space-vector
-+.
-+.  doc-print-recursive
-+..
-+.
-+.
- .\" NS Fx user macro
- .\" NS   print FreeBSD
- .\" NS
index 5963e73..2024711 100644 (file)
@@ -1119,6 +1119,176 @@ compute_stats(struct devstat *current, struct devstat *previous,
        return(0);
 }
 
+int
+compute_stats_read(struct devstat *current, struct devstat *previous,
+             long double etime, u_int64_t *total_bytes,
+             u_int64_t *total_transfers, u_int64_t *total_blocks,
+             long double *kb_per_transfer, long double *transfers_per_second,
+             long double *mb_per_second, long double *blocks_per_second,
+             long double *ms_per_transaction)
+{
+       u_int64_t totalbytes, totaltransfers, totalblocks;
+
+       /*
+        * current is the only mandatory field.
+        */
+       if (current == NULL) {
+               sprintf(devstat_errbuf, "%s: current stats structure was NULL",
+                       __func__);
+               return(-1);
+       }
+
+       totalbytes = current->bytes_read -
+                    (previous ? previous->bytes_read : 0);
+
+       if (total_bytes)
+               *total_bytes = totalbytes;
+
+       totaltransfers = current->num_reads -
+                        (previous ? previous->num_reads : 0);
+       if (total_transfers)
+               *total_transfers = totaltransfers;
+
+       if (transfers_per_second) {
+               if (etime > 0.0) {
+                       *transfers_per_second = totaltransfers;
+                       *transfers_per_second /= etime;
+               } else
+                       *transfers_per_second = 0.0;
+       }
+
+       if (kb_per_transfer) {
+               *kb_per_transfer = totalbytes;
+               *kb_per_transfer /= 1024;
+               if (totaltransfers > 0)
+                       *kb_per_transfer /= totaltransfers;
+               else
+                       *kb_per_transfer = 0.0;
+       }
+
+       if (mb_per_second) {
+               *mb_per_second = totalbytes;
+               *mb_per_second /= 1024 * 1024;
+               if (etime > 0.0)
+                       *mb_per_second /= etime;
+               else
+                       *mb_per_second = 0.0;
+       }
+
+       totalblocks = totalbytes;
+       if (current->block_size > 0)
+               totalblocks /= current->block_size;
+       else
+               totalblocks /= 512;
+
+       if (total_blocks)
+               *total_blocks = totalblocks;
+
+       if (blocks_per_second) {
+               *blocks_per_second = totalblocks;
+               if (etime > 0.0)
+                       *blocks_per_second /= etime;
+               else
+                       *blocks_per_second = 0.0;
+       }
+
+       if (ms_per_transaction) {
+               if (totaltransfers > 0) {
+                       *ms_per_transaction = etime;
+                       *ms_per_transaction /= totaltransfers;
+                       *ms_per_transaction *= 1000;
+               } else
+                       *ms_per_transaction = 0.0;
+       }
+
+       return(0);
+}
+
+int
+compute_stats_write(struct devstat *current, struct devstat *previous,
+             long double etime, u_int64_t *total_bytes,
+             u_int64_t *total_transfers, u_int64_t *total_blocks,
+             long double *kb_per_transfer, long double *transfers_per_second,
+             long double *mb_per_second, long double *blocks_per_second,
+             long double *ms_per_transaction)
+{
+       u_int64_t totalbytes, totaltransfers, totalblocks;
+
+       /*
+        * current is the only mandatory field.
+        */
+       if (current == NULL) {
+               sprintf(devstat_errbuf, "%s: current stats structure was NULL",
+                       __func__);
+               return(-1);
+       }
+
+       totalbytes = current->bytes_written -
+                    (previous ? previous->bytes_written : 0);
+
+       if (total_bytes)
+               *total_bytes = totalbytes;
+
+       totaltransfers = current->num_writes -
+                        (previous ? previous->num_writes : 0);
+       if (total_transfers)
+               *total_transfers = totaltransfers;
+
+       if (transfers_per_second) {
+               if (etime > 0.0) {
+                       *transfers_per_second = totaltransfers;
+                       *transfers_per_second /= etime;
+               } else
+                       *transfers_per_second = 0.0;
+       }
+
+       if (kb_per_transfer) {
+               *kb_per_transfer = totalbytes;
+               *kb_per_transfer /= 1024;
+               if (totaltransfers > 0)
+                       *kb_per_transfer /= totaltransfers;
+               else
+                       *kb_per_transfer = 0.0;
+       }
+
+       if (mb_per_second) {
+               *mb_per_second = totalbytes;
+               *mb_per_second /= 1024 * 1024;
+               if (etime > 0.0)
+                       *mb_per_second /= etime;
+               else
+                       *mb_per_second = 0.0;
+       }
+
+       totalblocks = totalbytes;
+       if (current->block_size > 0)
+               totalblocks /= current->block_size;
+       else
+               totalblocks /= 512;
+
+       if (total_blocks)
+               *total_blocks = totalblocks;
+
+       if (blocks_per_second) {
+               *blocks_per_second = totalblocks;
+               if (etime > 0.0)
+                       *blocks_per_second /= etime;
+               else
+                       *blocks_per_second = 0.0;
+       }
+
+       if (ms_per_transaction) {
+               if (totaltransfers > 0) {
+                       *ms_per_transaction = etime;
+                       *ms_per_transaction /= totaltransfers;
+                       *ms_per_transaction *= 1000;
+               } else
+                       *ms_per_transaction = 0.0;
+       }
+
+       return(0);
+}
+
 long double
 compute_etime(struct timeval cur_time, struct timeval prev_time)
 {
index 60866ff..4447597 100644 (file)
@@ -107,6 +107,20 @@ int compute_stats(struct devstat *current, struct devstat *previous,
                  long double *transfers_per_second, long double *mb_per_second,
                  long double *blocks_per_second,
                  long double *ms_per_transaction);
+int compute_stats_read(struct devstat *current, struct devstat *previous,
+                 long double etime, u_int64_t *total_bytes,
+                 u_int64_t *total_transfers, u_int64_t *total_blocks,
+                 long double *kb_per_transfer,
+                 long double *transfers_per_second, long double *mb_per_second,
+                 long double *blocks_per_second,
+                 long double *ms_per_transaction);
+int compute_stats_write(struct devstat *current, struct devstat *previous,
+                 long double etime, u_int64_t *total_bytes,
+                 u_int64_t *total_transfers, u_int64_t *total_blocks,
+                 long double *kb_per_transfer,
+                 long double *transfers_per_second, long double *mb_per_second,
+                 long double *blocks_per_second,
+                 long double *ms_per_transaction);
 long double compute_etime(struct timeval cur_time, struct timeval prev_time);
 __END_DECLS
 
index 15b62ee..c5adf3a 100644 (file)
@@ -6,7 +6,7 @@
 .Dt MQ_RECEIVE 2
 .Os
 .Sh NAME
-.Nm mq_receive, mq_timedreceive
+.Nm mq_receive , mq_timedreceive
 .Nd receive a message from a message queue (REALTIME)
 .Sh LIBRARY
 .Lb librt
index 1b8d108..ebd8016 100644 (file)
@@ -1182,7 +1182,7 @@ New undo/flush, giving faster sync.
 .Sh ENVIRONMENT
 If the following environment variables exist, they will be used by
 .Nm :
-.Bl
+.Bl -tag -width ".Ev EDITOR"
 .It Ev EDITOR
 The editor program specified in the variable
 .Ev EDITOR
index 749a1b0..241d4f3 100644 (file)
@@ -203,6 +203,7 @@ MAN=        aac.4 \
        pfsync.4 \
        pim.4 \
        polling.4 \
+       powernow.4 \
        ppbus.4 \
        ppc.4 \
        ppi.4 \
@@ -334,6 +335,7 @@ MAN=        aac.4 \
        vr.4 \
        watchdog.4 \
        wb.4 \
+       wbsio.4 \
        wi.4 \
        wlan.4 \
        wlan_acl.4 \
index 28f5989..709358f 100644 (file)
@@ -159,6 +159,8 @@ ITE IT8705F/IT8712F/IT8716F/IT8718F/IT8726F and SiS SiS950
 temperature, voltage, and fan sensor with watchdog timer
 .It Xr lm 4
 National Semiconductor LM78/79/81 temperature, voltage, and fan sensor
+.It Xr wbsio 4
+Winbond LPC Super I/O
 .El
 .Ss Miscellaneous devices
 .Bl -tag -width 12n -offset indent -compact
index 45874b8..0366e3a 100644 (file)
@@ -36,7 +36,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd August 19, 2007
+.Dd March 8, 2010
 .Dt LM 4
 .Os
 .Sh NAME
 .Cd "device lm0 at isa? port 0x290"
 .Cd "device lm1 at isa? port 0x280"
 .Cd "device lm2 at isa? port 0x310"
+.Pp
+.Cd "device wbsio0 at isa? port 0x2e"
+.Cd "device wbsio1 at isa? port 0x4e"
+.Cd "device lm#3 at wbsio?"
 .Sh DESCRIPTION
 The
 .Nm
@@ -85,6 +89,8 @@ ASUS AS99127F
 .Sh SEE ALSO
 .Xr systat 1 ,
 .Xr sysctl 3 ,
+.Xr isa 4 ,
+.Xr wbsio 4 ,
 .Xr sensorsd 8 ,
 .Xr sysctl 8
 .Sh HISTORY
diff --git a/share/man/man4/wbsio.4 b/share/man/man4/wbsio.4
new file mode 100644 (file)
index 0000000..f4e9bb0
--- /dev/null
@@ -0,0 +1,64 @@
+.\"    $NetBSD: wbsio.4,v 1.1 2010/02/21 05:16:29 cnst Exp $
+.\"    $OpenBSD: wbsio.4,v 1.2 2008/02/17 16:48:47 jmc Exp $
+.\"
+.\" Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd March 8, 2010
+.Dt WBSIO 4
+.Os
+.Sh NAME
+.Nm wbsio
+.Nd Winbond LPC Super I/O
+.Sh SYNOPSIS
+.Cd "device wbsio0 at isa? port 0x2e"
+.Cd "device wbsio1 at isa? port 0x4e"
+.Cd "device lm"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Winbond LPC Super I/O ICs.
+Only the hardware monitoring function is currently supported.
+.Pp
+Support for the hardware monitor function is provided through the
+.Xr lm 4
+driver.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr isa 4 ,
+.Xr lm 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 4.3 .
+.Nx
+support was added in
+.Nx 6.0 .
+.Dx
+support was added in
+.Dx 2.5 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Mark Kettenis Aq kettenis@openbsd.org .
+It was adapted to
+.Nx
+and
+.Dx
+by
+.An Constantine A. Murenin ,
+University of Waterloo.
index 3e52f7b..9ef34ea 100644 (file)
@@ -389,6 +389,7 @@ MLINKS+=EVENTHANDLER.9 EVENTHANDLER_DECLARE.9 \
        EVENTHANDLER.9 EVENTHANDLER_REGISTER.9 \
        EVENTHANDLER.9 eventhandler_register.9
 MLINKS+=fetch.9 fubyte.9 \
+       fetch.9 casuword.9 \
        fetch.9 fusword.9 \
        fetch.9 fuword.9
 MLINKS+=firmware.9 firmware_image_load.9 \
@@ -525,6 +526,7 @@ MLINKS+=nlookup.9 naccess.9 \
        nlookup.9 nlookup_done.9 \
        nlookup.9 nlookup_init.9 \
        nlookup.9 nlookup_init_raw.9 \
+       nlookup.9 nlookup_init_root.9 \
        nlookup.9 nlookup_mp.9 \
        nlookup.9 nlookup_set_cred.9 \
        nlookup.9 nlookup_simple.9 \
@@ -679,13 +681,17 @@ MLINKS+=sysctl_ctx_init.9 sysctl_ctx_entry_add.9 \
        sysctl_ctx_init.9 sysctl_ctx_entry_find.9 \
        sysctl_ctx_init.9 sysctl_ctx_free.9
 MLINKS+=taskqueue.9 TASK_INIT.9 \
+       taskqueue.9 taskqueue_block.9 \
        taskqueue.9 taskqueue_create.9 \
+       taskqueue.9 taskqueue_drain.9 \
        taskqueue.9 TASKQUEUE_DECLARE.9 \
        taskqueue.9 TASKQUEUE_DEFINE.9 \
        taskqueue.9 taskqueue_enqueue.9 \
        taskqueue.9 taskqueue_find.9 \
        taskqueue.9 taskqueue_free.9 \
-       taskqueue.9 taskqueue_run.9
+       taskqueue.9 taskqueue_run.9 \
+       taskqueue.9 taskqueue_start_threads.9 \
+       taskqueue.9 taskqueue_unblock.9
 MLINKS+=time.9 boottime.9 \
        time.9 time_second.9
 MLINKS+=tvtohz.9 tvtohz_high.9 \
index bae7959..488f164 100644 (file)
 .\" $FreeBSD: src/share/man/man9/fetch.9,v 1.6.2.4 2001/12/17 11:30:18 ru Exp $
 .\" $DragonFly: src/share/man/man9/fetch.9,v 1.4 2007/04/07 19:29:52 swildner Exp $
 .\"
-.Dd January 7, 1996
+.Dd March 14, 2010
 .Dt FETCH 9
 .Os
 .Sh NAME
 .Nm fetch ,
+.Nm casuword ,
 .Nm fubyte ,
 .Nm fusword ,
 .Nm fuword
@@ -49,6 +50,8 @@
 .In sys/time.h
 .In sys/systm.h
 .In sys/resourcevar.h
+.Ft u_long
+.Fn casuword "u_long *base" "u_long oldval" "u_long newval"
 .Ft int
 .Fn fubyte "const void *base"
 .Ft int
@@ -63,7 +66,19 @@ functions are designed to copy small amounts of data from user-space.
 The
 .Nm
 routines provide the following functionality:
-.Bl -tag -width ".Fn fusword"
+.Bl -tag -width ".Fn casuword"
+.It Fn casuword
+Compares
+.Fa oldval
+with the word at
+.Fa base ,
+and if equal,
+.Fa base
+is set to
+.Fa newval .
+The old value at
+.Fa base
+is then returned.
 .It Fn fubyte
 Fetches a byte of data from the user-space address
 .Fa base .
index ad46286..106a831 100644 (file)
 .\"
 .\" $DragonFly: src/share/man/man9/nlookup.9,v 1.11 2008/02/09 09:45:03 swildner Exp $
 .\"
-.Dd May 26, 2009
+.Dd March 14, 2010
 .Os
 .Dt NLOOKUP 9
 .Sh NAME
 .Nm nlookup ,
 .Nm nlookup_init ,
 .Nm nlookup_init_raw ,
+.Nm nlookup_init_root ,
 .Nm nlookup_set_cred ,
 .Nm nlookup_zero ,
 .Nm nlookup_done ,
@@ -55,6 +56,8 @@
 .Fn nlookup_init "struct nlookupdata *nd" "const char *path" "enum uio_seg seg" "int flags"
 .Ft int
 .Fn nlookup_init_raw "struct nlookupdata *nd" "const char *path" "enum uio_seg seg" "int flags" "struct ucred *cred" "struct namecache *ncstart"
+.Ft int
+.Fn nlookup_init_root "struct nlookupdata *nd" "const char *path" "enum uio_seg seg" "int flags" "struct ucred *cred" "struct namecache *ncstart" "struct namecache *ncroot"
 .Ft void
 .Fn nlookup_set_cred "struct nlookupdata *nd" "struct ucred *cred"
 .Ft void
@@ -118,6 +121,13 @@ rootncp is always chosen for the root directory and the
 .Fa cred
 and starting directory are supplied in the arguments.
 .Pp
+.Fn nlookup_init_root
+works similarly to
+.Fn nlookup_init_raw
+but does not assume rootnch for the root directory.
+The root directory is supplied in the arguments, and is also
+used for the jail directory.
+.Pp
 .Fn nlookup_set_cred
 sets a different credential; this credential will be used by
 future operations performed on nd.nl_open_vp
index e144fea..337fc5b 100644 (file)
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\" $FreeBSD: src/share/man/man9/taskqueue.9,v 1.21 2007/07/09 06:24:10 jmg Exp $
-.\" $DragonFly: src/share/man/man9/taskqueue.9,v 1.2 2007/11/07 21:38:00 swildner Exp $
 .\"
-.Dd August 10, 2007
+.Dd October 2, 2009
 .Dt TASKQUEUE 9
 .Os
 .Sh NAME
+.Nm taskqueue_block ,
 .Nm taskqueue_create ,
+.Nm tastqueue_drain ,
+.Nm taskqueue_enqueue ,
 .Nm taskqueue_free ,
 .Nm taskqueue_find ,
-.Nm taskqueue_enqueue ,
 .Nm taskqueue_run ,
+.Nm taskqueue_start_threads ,
+.Nm taskqueue_unblock ,
 .Nm TASK_INIT ,
 .Nm TASKQUEUE_DECLARE ,
 .Nm TASKQUEUE_DEFINE
@@ -159,10 +162,11 @@ enqueued after call to
 .Pp
 The
 .Fn taskqueue_block
-function is used to block a taskqueue. When a taskqueue
-is blocked, calls to enqueue will still enqueue tasks but
-they will not be run until the taskqueue is unblocked by
-calling
+function is used to block a taskqueue.
+When a taskqueue is blocked, calls to
+.Fn taskqueue_enqueue
+will still enqueue tasks but
+they will not be run until the taskqueue is unblocked by calling
 .Fn taskqueue_unblock .
 .Pp
 The
@@ -178,7 +182,7 @@ and the name given by
 with _N appended to it, where N is the number of the thread.
 If
 .Fa count
- > 1 and
+\*(Gt 1 and
 .Fa ncpu
 is -1, each of the
 .Fa count
@@ -232,13 +236,15 @@ allowing any further initialisation to be performed
 (such as registering an interrupt handler etc.)
 .Pp
 The system provides two global taskqueues,
-.Va taskqueue_swi ,
+.Va taskqueue_swi
+and
 .Va taskqueue_swi_mp ,
 which are run via a software interrupt mechanism.
 To use these queues, call
 .Fn taskqueue_enqueue
 with the value of the global variable
-.Va taskqueue_swi or
+.Va taskqueue_swi
+or
 .Va taskqueue_swi_mp .
 .Pp
 While
index cca09c8..afbe2b9 100644 (file)
@@ -1,4 +1,4 @@
-# @(#)asia     8.51
+# @(#)asia     8.55
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -225,11 +225,31 @@ Zone      Asia/Bahrain    3:22:20 -       LMT     1920            # Al Manamah
 # until further notice." I take that last sentence as the
 # establishment of a rule.
 
+# From Nobutomo Nakano (2010-02-19):
+# We received a report from Bangladesh saying that the start/end of
+# Bangladesh DST is incorrect. Currently we have only the Bengali version
+# of the official mail from BTRC which describes the following:
+#
+# "From 2010 each year when local standard time is about to reach
+# March 31 at 10:59:00 PM clocks are turned forward 1 hour (11:59:00 PM)
+# and when local daylight time is about to October 31 at 11:59:00 PM
+# clocks are turned backward 1 hour (10:59:00 PM)."
+#
+# So, DST will start/end 1 minute earlier.
+
+# From Arthur David Olson (2010-03-03):
+# The file
+# <a href=http://www.cabinet.gov/bd/file_upload/news_events/en_169.pdf>
+# http://www.cabinet.gov/bd/file_upload/news_events/en_169.pdf
+# </a>
+# is in Bengali; it does contain two "31"s as well as two "11.59"s and a "10.59"
+# which is consistent with the information provided by Nobutomo Nakano.
+
 # Rule NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
 Rule   Dhaka   2009    only    -       Jun     19      23:00   1:00    S
-Rule   Dhaka   2010    only    -       Jan     1       0:00    0       -
-Rule   Dhaka   2010    max     -       Mar     31      23:00   1:00    S
-Rule   Dhaka   2010    max     -       Nov     1       0:00    0       -
+Rule   Dhaka   2009    only    -       Dec     31      23:59   0       -
+Rule   Dhaka   2010    max     -       Mar     31      22:59   1:00    S
+Rule   Dhaka   2010    max     -       Oct     31      23:59   0       -
 
 # Zone NAME            GMTOFF  RULES   FORMAT  [UNTIL]
 Zone   Asia/Dhaka      6:01:40 -       LMT     1890
index bd57dee..5bb7bcd 100644 (file)
@@ -1,5 +1,5 @@
 # <pre>
-# @(#)australasia      8.15
+# @(#)australasia      8.16
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -267,11 +267,30 @@ Zone      Indian/Cocos    6:27:40 -       LMT     1900
 # <a href="http://www.fiji.gov.fj/publish/page_16198.shtml">
 # http://www.fiji.gov.fj/publish/page_16198.shtml
 # </a>
+
+# From Steffen Thorsen (2010-03-03):
+# The Cabinet in Fiji has decided to end DST about a month early, on
+# 2010-03-28 at 03:00.
+# The plan is to observe DST again, from 2010-10-24 to sometime in March
+# 2011 (last Sunday a good guess?).
+#
+# Official source:
+# <a href="http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166">
+# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166
+# </a>
+#
+# A bit more background info here:
+# <a href="http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html">
+# http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
+# </a>
+
 # Rule NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
 Rule   Fiji    1998    1999    -       Nov     Sun>=1  2:00    1:00    S
 Rule   Fiji    1999    2000    -       Feb     lastSun 3:00    0       -
 Rule   Fiji    2009    only    -       Nov     29      2:00    1:00    S
-Rule   Fiji    2010    only    -       Apr     25      3:00    0       -
+Rule   Fiji    2010    only    -       Mar     lastSun 3:00    0       -
+Rule   Fiji    2010    only    -       Oct     24      2:00    1:00    S
+Rule   Fiji    2011    only    -       Mar     lastSun 3:00    0       -
 # Zone NAME            GMTOFF  RULES   FORMAT  [UNTIL]
 Zone   Pacific/Fiji    11:53:40 -      LMT     1915 Oct 26     # Suva
                        12:00   Fiji    FJ%sT   # Fiji Time
@@ -449,70 +468,30 @@ Zone Pacific/Pago_Pago     12:37:12 -     LMT     1879 Jul  5
 
 # Samoa
 
-# From Alexander Krivenyshev (2008-12-06):
-# The Samoa government (Western Samoa) may implement DST on the first Sunday of
-# October 2009 (October 4, 2009) until the last Sunday of March 2010 (March 28,
-# 2010).
+# From Steffen Thorsen (2009-10-16):
+# We have been in contact with the government of Samoa again, and received
+# the following info:
 #
-# "Selected Committee reports to Cabinet on Daylight Saving Time",
-# Government of Samoa:
-# <a href="http://www.govt.ws/pr_article.cfm?pr_id=560">
-# http://www.govt.ws/pr_article.cfm?pr_id=560
-# </a>
-# or
-# <a href="http://www.worldtimezone.com/dst_news/dst_news_samoa01.html">
-# http://www.worldtimezone.com/dst_news/dst_news_samoa01.html
-# </a>
-
-# From Steffen Thorsen (2009-08-27):
-# Samoa's parliament passed the Daylight Saving Bill 2009, and will start
-# daylight saving time on the first Sunday of October 2009 and end on the
-# last Sunday of March 2010. We hope that the full text will be published
-# soon, but we believe that the bill is only valid for 2009-2010. Samoa's
-# Daylight Saving Act 2009 will be enforced as soon as the Head of State
-# executes a proclamation publicizing this Act.
+# "Cabinet has now approved Daylight Saving to be effected next year
+# commencing from the last Sunday of September 2010 and conclude first
+# Sunday of April 2011."
 #
-# Some background information here, which will be updated once we have
-# more details:
+# Background info:
 # <a href="http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html">
 # http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
 # </a>
-
-# From Alexander Krivenyshev (2009-10-03):
-# First, my deepest condolences to people of Samoa islands and all families and
-# loved ones around the world who lost their lives in the earthquake and tsunami.
-#
-# Considering the recent devastation on Samoa by earthquake and tsunami and that
-# many government offices/ ministers are closed- not sure if "Daylight Saving
-# Bill 2009" will be implemented in next few days- on October 4, 2009.
-#
-# Here is reply from Consulate-General of Samoa in New Zealand
-# ---------------------------
-# Consul General
-# consulgeneral@samoaconsulate.org.nz
-#
-# Talofa Alexander,
 #
-# Thank you for your sympathy for our country but at this time we have not
-# been informed about the Daylight Savings Time Change.  Most Ministries in
-# Apia are closed or relocating due to weather concerns.
-#
-# When we do find out if they are still proceeding with the time change we
-# will advise you soonest.
-#
-# Kind Regards,
-# Lana
-# for: Consul General
-
-# From Steffen Thorsen (2009-10-05):
-# We have called a hotel in Samoa and asked about local time there - they
-# are still on standard time.
+# Samoa's Daylight Saving Time Act 2009 is available here, but does not
+# contain any dates:
+# <a href="http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf">
+# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
+# </a>
 
 Zone Pacific/Apia       12:33:04 -     LMT     1879 Jul  5
                        -11:26:56 -     LMT     1911
                        -11:30  -       SAMT    1950            # Samoa Time
-                       -11:00  -       WST     2009 Oct 4
-                       -11:00  1:00    WSDT    2010 Mar 28
+                       -11:00  -       WST     2010 Oct 24
+                       -11:00  1:00    WSDT    2011 Apr 3
                        -11:00  -       WST
 
 # Solomon Is
index 5cd05d5..a166171 100644 (file)
@@ -1,5 +1,5 @@
 # <pre>
-# @(#)southamerica     8.41
+# @(#)southamerica     8.43
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 
@@ -1121,6 +1121,18 @@ Zone America/Rio_Branco  -4:31:12 -      LMT     1914
 # http://www.shoa.cl/noticias/2008/04hora/hora.htm
 # </a>.
 
+# From Angel Chiang (2010-03-04):
+# Subject: DST in Chile exceptionally extended to 3 April due to earthquake
+# <a href="http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098">
+# http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098
+# </a>
+# (in Spanish, last paragraph).
+#
+# This is breaking news. There should be more information available later.
+
+# From Arthur Daivd Olson (2010-03-06):
+# Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
+
 # Rule NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
 Rule   Chile   1927    1932    -       Sep      1      0:00    1:00    S
 Rule   Chile   1928    1932    -       Apr      1      0:00    0       -
@@ -1155,7 +1167,9 @@ Rule      Chile   2000    2007    -       Mar     Sun>=9  3:00u   0       -
 # N.B.: the end of March 29 in Chile is March 30 in Universal time,
 # which is used below in specifying the transition.
 Rule   Chile   2008    only    -       Mar     30      3:00u   0       -
-Rule   Chile   2009    max     -       Mar     Sun>=9  3:00u   0       -
+Rule   Chile   2009    only    -       Mar     Sun>=9  3:00u   0       -
+Rule   Chile   2010    only    -       Apr      4      3:00u   0       -
+Rule   Chile   2011    max     -       Mar     Sun>=9  3:00u   0       -
 # IATA SSIM anomalies: (1992-02) says 1992-03-14;
 # (1996-09) says 1998-03-08.  Ignore these.
 # Zone NAME            GMTOFF  RULES   FORMAT  [UNTIL]
@@ -1380,7 +1394,7 @@ Rule      Para    2005    2009    -       Mar     Sun>=8  0:00    0       -
 # and that on the first Sunday of the month of October, it is to be set
 # forward 60 minutes, in all the territory of the Paraguayan Republic.
 # ...
-Rule   Para    2010    max     -       Oct     Sun<=7  0:00    1:00    S
+Rule   Para    2010    max     -       Oct     Sun>=1  0:00    1:00    S
 Rule   Para    2010    max     -       Apr     Sun>=8  0:00    0       -
 
 # Zone NAME            GMTOFF  RULES   FORMAT  [UNTIL]
index 3315d36..2cbfe78 100644 (file)
@@ -1484,6 +1484,14 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
        }
        actual = i;
 
+       if (actual == 0) {
+               if (bootverbose) {
+                       device_printf(child,
+                           "could not allocate any MSI-X vectors\n");
+               }
+               return  (ENXIO);
+       }
+
        if (bootverbose) {
                rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1);
                if (actual == 1)
index 17165c8..388119e 100644 (file)
@@ -689,7 +689,6 @@ kern/kern_memio.c   standard
 kern/kern_upcall.c     standard
 kern/kern_sfbuf.c      standard
 kern/kern_mplock.c     standard
-kern/kern_msfbuf.c     standard
 kern/kern_subr.c       standard
 kern/kern_iosched.c    standard
 kern/kern_usched.c     standard
@@ -1724,6 +1723,7 @@ dev/powermng/aps/aps.c                    optional aps isa
 dev/powermng/it/it.c                   optional it isa
 dev/powermng/lm/lm78.c                 optional lm isa
 dev/powermng/lm/lm78_isa.c             optional lm isa
+dev/powermng/wbsio/wbsio.c             optional wbsio isa
 emulation/43bsd/43bsd_socket.c         optional compat_43
 emulation/43bsd/43bsd_stats.c          optional compat_43
 emulation/43bsd/43bsd_file.c           optional compat_43
index 56b0f14..8dadeab 100644 (file)
@@ -195,6 +195,9 @@ device              it0     at isa? port 0x290
 device         it1     at isa? port 0xc00
 device         it2     at isa? port 0xd00
 device         it3     at isa? port 0x228
+device         wbsio0  at isa? port 0x2e
+device         wbsio1  at isa? port 0x4e
+device         lm#3    at wbsio?
 
 # PCCARD (PCMCIA) support
 device         pccard
index 41d68de..80aac2f 100644 (file)
@@ -2112,6 +2112,9 @@ device            it2     at isa? port 0xd00
 device         it3     at isa? port 0x228
 device         nsclpcsio0 at isa? port 0x2e
 device         nsclpcsio1 at isa? port 0x4e
+device         wbsio0  at isa? port 0x2e
+device         wbsio1  at isa? port 0x4e
+device         lm#3    at wbsio?
 
 #---------------------------------------------------------------------------
 # ISDN4BSD
index 887e9d1..8e3748f 100644 (file)
@@ -170,6 +170,9 @@ device              it0     at isa? port 0x290
 device         it1     at isa? port 0xc00
 device         it2     at isa? port 0xd00
 device         it3     at isa? port 0x228
+device         wbsio0  at isa? port 0x2e
+device         wbsio1  at isa? port 0x4e
+device         lm#3    at wbsio?
 
 # PCCARD (PCMCIA) support
 device         pccard
index 54e097d..1b8bf29 100644 (file)
@@ -533,6 +533,8 @@ ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt)
                kprintf("%s: enabling aggressive link power management.\n",
                        PORTNAME(ap));
 
+               ap->link_pwr_mgmt = link_pwr_mgmt;
+
                ap->ap_intmask &= ~AHCI_PREG_IE_PRCE;
                ahci_port_interrupt_enable(ap);
 
@@ -540,23 +542,36 @@ ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt)
                sctl &= ~(AHCI_PREG_SCTL_IPM_DISABLED);
                ahci_pwrite(ap, AHCI_PREG_SCTL, sctl);
 
+               /*
+                * Enable device initiated link power management for
+                * directly attached devices that support it.
+                */
+               if (ap->ap_type != ATA_PORT_T_PM &&
+                   ap->ap_ata[0]->at_identify.satafsup & (1 << 3)) {
+                       if (ahci_set_feature(ap, NULL, ATA_SATAFT_DEVIPS, 1))
+                               kprintf("%s: Could not enable device initiated "
+                                   "link power management.\n",
+                                   PORTNAME(ap));
+               }
+
                cmd = ahci_pread(ap, AHCI_PREG_CMD);
                cmd |= AHCI_PREG_CMD_ASP;
                cmd |= AHCI_PREG_CMD_ALPE;
                ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
 
-               ap->link_pwr_mgmt = link_pwr_mgmt;
-
        } else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_MEDIUM &&
                   (ap->ap_sc->sc_cap & AHCI_REG_CAP_PSC)) {
                kprintf("%s: enabling medium link power management.\n",
                        PORTNAME(ap));
 
+               ap->link_pwr_mgmt = link_pwr_mgmt;
+
                ap->ap_intmask &= ~AHCI_PREG_IE_PRCE;
                ahci_port_interrupt_enable(ap);
 
                sctl = ahci_pread(ap, AHCI_PREG_SCTL);
-               sctl &= ~(AHCI_PREG_SCTL_IPM_DISABLED);
+               sctl |= AHCI_PREG_SCTL_IPM_DISABLED;
+               sctl &= ~AHCI_PREG_SCTL_IPM_NOPARTIAL;
                ahci_pwrite(ap, AHCI_PREG_SCTL, sctl);
 
                cmd = ahci_pread(ap, AHCI_PREG_CMD);
@@ -564,14 +579,16 @@ ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt)
                cmd |= AHCI_PREG_CMD_ALPE;
                ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
 
-               ap->link_pwr_mgmt = link_pwr_mgmt;
-
        } else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_NONE) {
                kprintf("%s: disabling link power management.\n",
                        PORTNAME(ap));
 
+               /* Disable device initiated link power management */
+               if (ap->ap_type != ATA_PORT_T_PM &&
+                   ap->ap_ata[0]->at_identify.satafsup & (1 << 3))
+                       ahci_set_feature(ap, NULL, ATA_SATAFT_DEVIPS, 0);
+
                cmd = ahci_pread(ap, AHCI_PREG_CMD);
-               cmd |= AHCI_PREG_CMD_ASP;
                cmd &= ~(AHCI_PREG_CMD_ALPE | AHCI_PREG_CMD_ASP);
                ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
 
@@ -584,7 +601,8 @@ ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt)
                ahci_os_sleep(1000);
                ahci_os_lock_port(ap);
 
-               ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_N);
+               ahci_pwrite(ap, AHCI_PREG_SERR,
+                   AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_W);
                ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS);
 
                ap->ap_intmask |= AHCI_PREG_IE_PRCE;
@@ -599,6 +617,26 @@ ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt)
        ahci_os_unlock_port(ap);
 }
 
+/*
+ * Return current link power state.
+ */
+int
+ahci_port_link_pwr_state(struct ahci_port *ap)
+{
+       uint32_t r;
+
+       r = ahci_pread(ap, AHCI_PREG_SSTS);
+       switch (r & SATA_PM_SSTS_IPM) {
+       case SATA_PM_SSTS_IPM_ACTIVE:
+               return 1;
+       case SATA_PM_SSTS_IPM_PARTIAL:
+               return 2;
+       case SATA_PM_SSTS_IPM_SLUMBER:
+               return 3;
+       default:
+               return 0;
+       }
+}
 
 /*
  * Run the port / target state machine from a main context.
@@ -2273,6 +2311,13 @@ ahci_port_intr(struct ahci_port *ap, int blockable)
                ap->ap_sactive, ahci_pread(ap, AHCI_PREG_SACT));
 #endif
 
+       /* ignore AHCI_PREG_IS_PRCS when link power management is on */
+       if (ap->link_pwr_mgmt != AHCI_LINK_PWR_MGMT_NONE) {
+               is &= ~AHCI_PREG_IS_PRCS;
+               ahci_pwrite(ap, AHCI_PREG_SERR,
+                   AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_W);
+       }
+
        if (is & AHCI_PREG_IS_TFES) {
                /*
                 * Command failed (blockable).
@@ -2526,11 +2571,6 @@ finish_error:
         *           and restarted.
         */
 
-       /* ignore AHCI_PREG_IS_PRCS when link power management is on */
-       if (ap->link_pwr_mgmt != AHCI_LINK_PWR_MGMT_NONE) {
-               is &= ~AHCI_PREG_IS_PRCS;
-       }
-
        if (is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)) {
                kprintf("%s: Transient Errors: %b\n",
                        PORTNAME(ap), is, AHCI_PFMT_IS);
@@ -3431,3 +3471,35 @@ static void
 ahci_empty_done(struct ahci_ccb *ccb)
 {
 }
+
+int
+ahci_set_feature(struct ahci_port *ap, struct ata_port *atx, int feature, int enable)
+{
+       struct ata_port *at;
+       struct ata_xfer *xa;
+       int error;
+
+       at = atx ? atx : ap->ap_ata[0];
+
+       xa = ahci_ata_get_xfer(ap, atx);
+
+       xa->fis->type = ATA_FIS_TYPE_H2D;
+       xa->fis->flags = ATA_H2D_FLAGS_CMD | at->at_target;
+       xa->fis->command = ATA_C_SET_FEATURES;
+       xa->fis->features = enable ? ATA_C_SATA_FEATURE_ENA :
+                                    ATA_C_SATA_FEATURE_DIS;
+       xa->fis->sector_count = feature;
+       xa->fis->control = ATA_FIS_CONTROL_4BIT;
+
+       xa->complete = ahci_dummy_done;
+       xa->datalen = 0;
+       xa->flags = ATA_F_POLL;
+       xa->timeout = 1000;
+
+       if (ahci_ata_cmd(xa) == ATA_S_COMPLETE)
+               error = 0;
+       else
+               error = EIO;
+       ahci_ata_put_xfer(xa);
+       return(error);
+}
index 7d56db7..e1f7c0c 100644 (file)
@@ -507,6 +507,7 @@ void        ahci_port_state_machine(struct ahci_port *ap, int initial);
 void   ahci_port_free(struct ahci_softc *, u_int);
 int    ahci_port_reset(struct ahci_port *, struct ata_port *at, int);
 void   ahci_port_link_pwr_mgmt(struct ahci_port *, int link_pwr_mgmt);
+int    ahci_port_link_pwr_state(struct ahci_port *);
 
 u_int32_t ahci_read(struct ahci_softc *, bus_size_t);
 void   ahci_write(struct ahci_softc *, bus_size_t, u_int32_t);
@@ -522,6 +523,8 @@ int ahci_port_start(struct ahci_port *ap);
 int    ahci_port_stop(struct ahci_port *ap, int stop_fis_rx);
 int    ahci_port_clo(struct ahci_port *ap);
 void   ahci_flush_tfd(struct ahci_port *ap);
+int    ahci_set_feature(struct ahci_port *ap, struct ata_port *atx,
+                       int feature, int enable);
 
 int    ahci_cam_attach(struct ahci_port *ap);
 void   ahci_cam_changed(struct ahci_port *ap, struct ata_port *at, int found);
@@ -535,7 +538,6 @@ int ahci_ata_cmd(struct ata_xfer *xa);
 int     ahci_pm_port_probe(struct ahci_port *ap, int);
 int    ahci_pm_port_init(struct ahci_port *ap, struct ata_port *at);
 int    ahci_pm_identify(struct ahci_port *ap);
-int    ahci_pm_set_feature(struct ahci_port *ap, int feature, int enable);
 int    ahci_pm_hardreset(struct ahci_port *ap, int target, int hard);
 int    ahci_pm_softreset(struct ahci_port *ap, int target);
 int    ahci_pm_phy_status(struct ahci_port *ap, int target, u_int32_t *datap);
index 633fdb7..407827c 100644 (file)
@@ -47,7 +47,7 @@ u_int32_t AhciNoFeatures = 0;
 static int     ahci_probe (device_t dev);
 static int     ahci_attach (device_t dev);
 static int     ahci_detach (device_t dev);
-static int     ahci_systcl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS);
+static int     ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS);
 #if 0
 static int     ahci_shutdown (device_t dev);
 static int     ahci_suspend (device_t dev);
@@ -149,7 +149,7 @@ ahci_detach (device_t dev)
 }
 
 static int
-ahci_systcl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS)
+ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS)
 {
        struct ahci_port *ap = arg1;
        int error, link_pwr_mgmt;
@@ -163,6 +163,22 @@ ahci_systcl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS)
        return 0;
 }
 
+static int
+ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS)
+{
+       struct ahci_port *ap = arg1;
+       const char *state_names[] = {"unknown", "active", "partial", "slumber"};
+       char buf[16];
+       int state;
+
+       state = ahci_port_link_pwr_state(ap);
+       if (state < 0 || state >= sizeof(state_names) / sizeof(state_names[0]))
+               state = 0;
+
+       ksnprintf(buf, sizeof(buf), "%s", state_names[state]);
+       return sysctl_handle_string(oidp, buf, sizeof(buf), req);
+}
+
 #if 0
 
 static int
@@ -240,9 +256,14 @@ ahci_os_start_port(struct ahci_port *ap)
                SYSCTL_ADD_PROC(&ap->sysctl_ctx,
                        SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO,
                        "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0,
-                       ahci_systcl_link_pwr_mgmt, "I",
-                       "Link power management "
+                       ahci_sysctl_link_pwr_mgmt, "I",
+                       "Link power management policy "
                        "(0 = disabled, 1 = medium, 2 = aggressive)");
+               SYSCTL_ADD_PROC(&ap->sysctl_ctx,
+                       SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO,
+                       "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0,
+                       ahci_sysctl_link_pwr_state, "A",
+                       "Link power management state");
 
        }
 
index 296d8bd..31a62a3 100644 (file)
@@ -738,34 +738,6 @@ ahci_pm_phy_status(struct ahci_port *ap, int target, u_int32_t *datap)
        return(error);
 }
 
-int
-ahci_pm_set_feature(struct ahci_port *ap, int feature, int enable)
-{
-       struct ata_xfer *xa;
-       int error;
-
-       xa = ahci_ata_get_xfer(ap, ap->ap_ata[15]);
-
-       xa->fis->type = ATA_FIS_TYPE_H2D;
-       xa->fis->flags = ATA_H2D_FLAGS_CMD | 15;
-       xa->fis->command = enable ? ATA_C_SATA_FEATURE_ENA :
-                                   ATA_C_SATA_FEATURE_DIS;
-       xa->fis->sector_count = feature;
-       xa->fis->control = ATA_FIS_CONTROL_4BIT;
-
-       xa->complete = ahci_pm_dummy_done;
-       xa->datalen = 0;
-       xa->flags = ATA_F_POLL;
-       xa->timeout = 1000;
-
-       if (ahci_ata_cmd(xa) == ATA_S_COMPLETE)
-               error = 0;
-       else
-               error = EIO;
-       ahci_ata_put_xfer(xa);
-       return(error);
-}
-
 /*
  * Check that a target is still good.
  */
index 0606368..2a16194 100644 (file)
@@ -83,6 +83,7 @@
 #include "e1000_api.h"
 #include "e1000_82571.h"
 #include "if_em.h"
+#include "ifcap_defines.h" // XXX
 
 /*********************************************************************
  *  Set this to one to display debug statistics
index ca8394f..8115031 100644 (file)
@@ -91,6 +91,7 @@
 #include "e1000_api.h"
 #include "e1000_82575.h"
 #include "if_igb.h"
+#include "ifcap_defines.h" // XXX
 
 /*********************************************************************
  *  Set this to one to display debug statistics
diff --git a/sys/dev/netif/e1000/ifcap_defines.h b/sys/dev/netif/e1000/ifcap_defines.h
new file mode 100644 (file)
index 0000000..5f55b98
--- /dev/null
@@ -0,0 +1,15 @@
+#define IFCAP_TSO4             0x00100 /* can do TCP Segmentation Offload */
+#define IFCAP_TSO6             0x00200 /* can do TCP6 Segmentation Offload */
+#define IFCAP_LRO              0x00400 /* can do Large Receive Offload */
+#define IFCAP_WOL_UCAST                0x00800 /* wake on any unicast frame */
+#define IFCAP_WOL_MCAST                0x01000 /* wake on any multicast frame */
+#define IFCAP_WOL_MAGIC                0x02000 /* wake on any Magic Packet */
+#define IFCAP_TOE4             0x04000 /* interface can offload TCP */
+#define IFCAP_TOE6             0x08000 /* interface can offload TCP6 */
+#define IFCAP_VLAN_HWFILTER    0x10000 /* interface hw can filter vlan tag */
+#define IFCAP_POLLING_NOCOUNT  0x20000 /* polling ticks cannot be fragmented */
+#define IFCAP_VLAN_HWTSO       0x40000 /* can do IFCAP_TSO on VLANs */
+
+#define IFCAP_TSO      (IFCAP_TSO4 | IFCAP_TSO6)
+#define IFCAP_WOL      (IFCAP_WOL_UCAST | IFCAP_WOL_MCAST | IFCAP_WOL_MAGIC)
+#define IFCAP_TOE      (IFCAP_TOE4 | IFCAP_TOE6)
diff --git a/sys/dev/powermng/wbsio/Makefile b/sys/dev/powermng/wbsio/Makefile
new file mode 100644 (file)
index 0000000..482d37d
--- /dev/null
@@ -0,0 +1,5 @@
+KMOD=          wbsio
+SRCS=          ${KMOD}.c
+SRCS+=         isa_if.h bus_if.h device_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/dev/powermng/wbsio/wbsio.c b/sys/dev/powermng/wbsio/wbsio.c
new file mode 100644 (file)
index 0000000..98ea7c2
--- /dev/null
@@ -0,0 +1,282 @@
+/*     $NetBSD: wbsio.c,v 1.1 2010/02/21 05:16:29 cnst Exp $   */
+/*     $OpenBSD: wbsio.c,v 1.5 2009/03/29 21:53:52 sthen Exp $ */
+/*
+ * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
+ * Copyright (c) 2010 Constantine A. Murenin <cnst++@dragonflybsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Winbond LPC Super I/O driver.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/systm.h>
+
+#include <bus/isa/isavar.h>
+
+/* ISA bus registers */
+#define WBSIO_INDEX            0x00    /* Configuration Index Register */
+#define WBSIO_DATA             0x01    /* Configuration Data Register */
+
+#define WBSIO_IOSIZE           0x02    /* ISA I/O space size */
+
+#define WBSIO_CONF_EN_MAGIC    0x87    /* enable configuration mode */
+#define WBSIO_CONF_DS_MAGIC    0xaa    /* disable configuration mode */
+
+/* Configuration Space Registers */
+#define WBSIO_LDN              0x07    /* Logical Device Number */
+#define WBSIO_ID               0x20    /* Device ID */
+#define WBSIO_REV              0x21    /* Device Revision */
+
+#define WBSIO_ID_W83627HF      0x52
+#define WBSIO_ID_W83627THF     0x82
+#define WBSIO_ID_W83627EHF     0x88
+#define WBSIO_ID_W83627DHG     0xa0
+#define WBSIO_ID_W83627SF      0x59
+#define WBSIO_ID_W83637HF      0x70
+#define WBSIO_ID_W83697HF      0x60
+
+/* Logical Device Number (LDN) Assignments */
+#define WBSIO_LDN_HM           0x0b
+
+/* Hardware Monitor Control Registers (LDN B) */
+#define WBSIO_HM_ADDR_MSB      0x60    /* Address [15:8] */
+#define WBSIO_HM_ADDR_LSB      0x61    /* Address [7:0] */
+
+struct wbsio_softc {
+       struct device           *sc_dev;
+
+       struct resource         *sc_iores;
+       int                     sc_iorid;
+
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+};
+
+static int     wbsio_probe(struct device *);
+static int     wbsio_attach(struct device *);
+static int     wbsio_detach(struct device *);
+
+static device_method_t wbsio_methods[] = {
+       DEVMETHOD(device_probe,         wbsio_probe),
+       DEVMETHOD(device_attach,        wbsio_attach),
+       DEVMETHOD(device_detach,        wbsio_detach),
+
+       { NULL, NULL}
+};
+
+static driver_t wbsio_driver = {
+       "wbsio",
+       wbsio_methods,
+       sizeof(struct wbsio_softc)
+};
+
+static devclass_t wbsio_devclass;
+
+DRIVER_MODULE(wbsio, isa, wbsio_driver, wbsio_devclass, NULL, NULL);
+
+
+static __inline void
+wbsio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh)
+{
+       bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC);
+       bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC);
+}
+
+static __inline void
+wbsio_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh)
+{
+       bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC);
+}
+
+static __inline u_int8_t
+wbsio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index)
+{
+       bus_space_write_1(iot, ioh, WBSIO_INDEX, index);
+       return (bus_space_read_1(iot, ioh, WBSIO_DATA));
+}
+
+static __inline void
+wbsio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index,
+    u_int8_t data)
+{
+       bus_space_write_1(iot, ioh, WBSIO_INDEX, index);
+       bus_space_write_1(iot, ioh, WBSIO_DATA, data);
+}
+
+static int
+wbsio_probe(struct device *dev)
+{
+       struct resource *iores;
+       int iorid = 0;
+       bus_space_tag_t iot;
+       bus_space_handle_t ioh;
+       uint8_t reg_id, reg_rev;
+       const char *desc = NULL;
+       char fulldesc[64];
+
+       /* Match by device ID */
+
+       iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
+           0ul, ~0ul, WBSIO_IOSIZE,
+           RF_ACTIVE);
+       if (iores == NULL)
+               return ENXIO;
+       iot = rman_get_bustag(iores);
+       ioh = rman_get_bushandle(iores);
+
+       wbsio_conf_enable(iot, ioh);
+       /* Read device ID */
+       reg_id = wbsio_conf_read(iot, ioh, WBSIO_ID);
+       /* Read device revision */
+       reg_rev = wbsio_conf_read(iot, ioh, WBSIO_REV);
+       wbsio_conf_disable(iot, ioh);
+       bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
+
+       switch (reg_id) {
+       case WBSIO_ID_W83627HF:
+               desc = "W83627HF";
+               break;
+       case WBSIO_ID_W83627THF:
+               desc = "W83627THF";
+               break;
+       case WBSIO_ID_W83627EHF:
+               desc = "W83627EHF";
+               break;
+       case WBSIO_ID_W83627DHG:
+               desc = "W83627DHG";
+               break;
+       case WBSIO_ID_W83637HF:
+               desc = "W83637HF";
+               break;
+       case WBSIO_ID_W83697HF:
+               desc = "W83697HF";
+               break;
+       }
+
+       if (desc == NULL)
+               return ENXIO;
+
+       ksnprintf(fulldesc, sizeof(fulldesc),
+           "Winbond LPC Super I/O %s rev 0x%02x", desc, reg_rev);
+       device_set_desc_copy(dev, fulldesc);
+       return 0;
+}
+
+static int
+wbsio_attach(struct device *dev)
+{
+       struct wbsio_softc *sc = device_get_softc(dev);
+       uint8_t reg0, reg1;
+       uint16_t iobase;
+       struct device *parent = device_get_parent(dev);
+       struct device *child;
+       struct devclass *c_dc;
+       int c_maxunit;
+
+       /* Map ISA I/O space */
+       sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
+           0ul, ~0ul, WBSIO_IOSIZE,
+           RF_ACTIVE);
+       if (sc->sc_iores == NULL) {
+               device_printf(dev, "can't map i/o space\n");
+               return ENXIO;
+       }
+       sc->sc_iot = rman_get_bustag(sc->sc_iores);
+       sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
+
+       /* Enter configuration mode */
+       wbsio_conf_enable(sc->sc_iot, sc->sc_ioh);
+
+       /* Select HM logical device */
+       wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM);
+
+       /*
+        * The address should be 8-byte aligned, but it seems some
+        * BIOSes ignore this.  They get away with it, because
+        * Apparently the hardware simply ignores the lower three
+        * bits.  We do the same here.
+        */
+       reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_LSB);
+       reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB);
+       iobase = (reg1 << 8) | (reg0 & ~0x7);
+       device_printf(dev, "hardware monitor iobase is 0x%x\n", iobase);
+
+       /* Escape from configuration mode */
+       wbsio_conf_disable(sc->sc_iot, sc->sc_ioh);
+
+       if (iobase == 0) {
+               device_printf(dev, "no hardware monitor configured\n");
+               return 0;
+       }
+
+       child = NULL;
+       c_dc = devclass_find("lm");
+       if (c_dc == NULL) {
+               device_printf(dev, "lm devclass not found\n");
+               return ENXIO;
+       }
+       c_maxunit = devclass_get_maxunit(c_dc);
+       for (int u = 0; u < c_maxunit; u++) {
+               child = devclass_get_device(c_dc, u);
+               if (child == NULL)
+                       continue;
+               if (isa_get_port(child) == iobase) {
+                       if (device_is_attached(child)) {
+                               device_printf(dev,
+                                   "%s is already attached at 0x%x\n",
+                                   device_get_nameunit(child), iobase);
+                               return 0;
+                       }
+                       break;
+               }
+               if (device_is_attached(child)) {
+                       child = NULL;
+                       continue;
+               }
+               device_printf(dev,
+                   "found unused %s at 0x%x with state %i, reusing at 0x%x\n",
+                   device_get_nameunit(child), isa_get_port(child),
+                   device_get_state(child), iobase);
+               break;
+       }
+       if (child == NULL)
+               child = BUS_ADD_CHILD(parent, parent, ISA_ORDER_PNP,
+                   "lm", -1);
+//     child = BUS_ADD_CHILD(parent, parent, ISA_ORDER_PNP,
+//         "lm", 3 + device_get_unit(dev));
+       if (child == NULL) {
+               device_printf(dev, "cannot add child\n");
+               return ENXIO;
+       }
+       if (bus_set_resource(child, SYS_RES_IOPORT, 0, iobase, 8)) {
+               device_printf(dev, "cannot set resource\n");
+               return ENXIO;
+       }
+       return device_probe_and_attach(child);
+}
+
+static int
+wbsio_detach(struct device *dev)
+{
+       struct wbsio_softc *sc = device_get_softc(dev);
+
+       return bus_release_resource(dev, SYS_RES_IOPORT,
+           sc->sc_iorid, sc->sc_iores);
+}
index 0f9af64..7a8974b 100644 (file)
@@ -5,11 +5,14 @@
 
 ARCH=  arch_linux
 KMOD=  linux
-SRCS=  linux_dummy.c linux_file.c linux_getcwd.c linux_ioctl.c linux_ipc.c \
-       linux_machdep.c linux_mib.c linux_misc.c linux_signal.c linux_socket.c \
+SRCS=  linux_dummy.c linux_emuldata.c linux_epoll.c \
+       linux_file.c linux_futex.c linux_getcwd.c linux_ioctl.c \
+       linux_ipc.c \
+       linux_machdep.c linux_mib.c linux_misc.c linux_time.c linux_signal.c \
+       linux_socket.c \
        linux_stats.c linux_sysctl.c linux_sysent.c linux_sysvec.c \
        linux_util.c opt_compat.h opt_global.h opt_vmpage.h
-OBJS=  linux_locore.o
+OBJS=  linux_support.o linux_locore.o
 
 SUBDIR= i386/linprocfs
 .if ${MACHINE_ARCH} == "i386"
@@ -28,6 +31,10 @@ linux_locore.o: linux_locore.s linux_assym.h
        ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
            ${.IMPSRC} -o ${.TARGET}
 
+linux_support.o: linux_support.s linux_assym.h
+       ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
+           ${.IMPSRC} -o ${.TARGET}
+
 linux_genassym.o: linux_genassym.c linux.h @
        ${CC} -c ${CFLAGS:N-fno-common} ${.IMPSRC}
 
index cff12cd..9651229 100644 (file)
@@ -58,7 +58,23 @@ typedef enum {
        Pstat,          /* kernel/system statistics */
        Puptime,        /* system uptime */
        Pversion,       /* system version */
-       Ploadavg        /* system load average */
+       Ploadavg,       /* system load average */
+       Pnet,           /* the net sub-directory */
+       Pnetdev,        /* net devices */
+       Psys,           /* the sys sub-directory */
+       Psyskernel,     /* the sys/kernel sub-directory */
+       Pdevices,       /* devices */
+       Posrelease,     /* osrelease */
+       Postype,        /* ostype */
+       Ppidmax,        /* pid_max */
+       Pcwd,
+       Pprocroot,
+       Pfd,
+       Pcmdline,
+       Penviron,
+       Pmaps,
+       Pstatm,
+       Pmounts,
 } pfstype;
 
 /*
@@ -130,13 +146,20 @@ int linprocfs_write_dbregs (struct proc *, struct dbreg *);
 #endif
 int linprocfs_domeminfo (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_docpuinfo (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
+int linprocfs_domounts (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_dostat (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_douptime (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_doversion (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_doprocstat (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_doprocstatus (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
 int linprocfs_doloadavg (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
-
+int linprocfs_donetdev (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
+int linprocfs_dodevices (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
+int linprocfs_doosrelease (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
+int linprocfs_doostype (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
+int linprocfs_dopidmax (struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio);
+int linprocfs_domaps(struct proc *curp, struct proc *p, struct pfsnode *pfs, struct uio *uio);
+int linprocfs_dostatm(struct proc *curp, struct proc *p, struct pfsnode *pfs, struct uio *uio);
 /* functions to check whether or not files should be displayed */
 int linprocfs_validfile (struct proc *);
 
index 6be0e01..75ee1a6 100644 (file)
@@ -53,6 +53,9 @@
 #include <sys/tty.h>
 #include <sys/vnode.h>
 #include <sys/lock.h>
+#include <sys/sbuf.h>
+#include <sys/mount.h>
+#include <sys/sysctl.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <machine/cputypes.h>
 #include <machine/inttypes.h>
 #include <machine/md_var.h>
+#include <machine/vmparam.h>
 
 #include "linprocfs.h"
+#include "../linux.h"
+#include "../../linux_ioctl.h"
+#include "../../linux_mib.h"
 
 /*
  * Various conversion macros
@@ -165,9 +172,14 @@ linprocfs_docpuinfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                    struct uio *uio)
 {
        char *ps;
-       char psbuf[512];                /* XXX - conservative */
+       char psbuf[8192];
+       char hwmodel[128];
+       size_t  modellen = sizeof(hwmodel);
+       int mib[] = { CTL_HW, HW_MODEL };
        int class;
+       int cpu;
         int i;
+       int error;
 #if 0
        extern char *cpu_model;         /* Yuck */
 #endif
@@ -211,13 +223,21 @@ linprocfs_docpuinfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        }
 
        ps = psbuf;
-       ps += ksprintf(ps,
-                       "processor\t: %d\n"
-                       "vendor_id\t: %.20s\n"
-                       "cpu family\t: %d\n"
-                       "model\t\t: %d\n"
-                       "stepping\t: %d\n",
-                       0, cpu_vendor, class, cpu, cpu_id & 0xf);
+
+       error = kernel_sysctl(mib, 2, hwmodel, &modellen, NULL, 0, NULL);
+       if (error)
+               strcpy(hwmodel, "unknown");
+
+       for (cpu = 0; cpu < ncpus; cpu++) {
+               ps += ksprintf(ps,
+                   "processor\t: %d\n"
+                   "vendor_id\t: %.20s\n"
+                   "cpu family\t: %d\n"
+                   "model\t\t: %d\n"
+                   "model name\t: %s\n"
+                   "stepping\t: %d\n",
+                   cpu, cpu_vendor, class, cpu, hwmodel, cpu_id & 0xf);
+       }
 
         ps += ksprintf(ps,
                         "flags\t\t:");
@@ -258,26 +278,98 @@ cpucnt(int offset)
     return(count);
 }
 
+static int
+linprocfs_domounts_callback(struct mount *mp, void *data)
+{
+       struct statfs *st;
+       struct sbuf *sb = (struct sbuf *)data;
+       char *to, *from, *fs;
+
+       st = &mp->mnt_stat;
+
+       from = st->f_mntfromname;
+       to = st->f_mntonname;
+       fs = st->f_fstypename;
+
+       if (!strcmp(st->f_fstypename, "linprocfs"))
+               fs = "proc";
+       else if (!strcmp(st->f_fstypename, "ext2fs"))
+               fs = "ext2";
+       else if (!strcmp(st->f_fstypename, "msdos"))
+               fs = "vfat";
+       else if (!strcmp(st->f_fstypename, "msdosfs"))
+               fs = "vfat";
+
+       sbuf_printf(sb, "%s %s %s %s", from, to, fs,
+           st->f_flags & MNT_RDONLY ? "ro" : "rw");
+
+#define OPT_ADD(name, flag) if (st->f_flags & (flag)) sbuf_printf(sb, "," name)
+       OPT_ADD("sync",         MNT_SYNCHRONOUS);
+       OPT_ADD("noexec",       MNT_NOEXEC);
+       OPT_ADD("nosuid",       MNT_NOSUID);
+       OPT_ADD("nodev",        MNT_NODEV);
+       OPT_ADD("async",        MNT_ASYNC);
+       OPT_ADD("suiddir",      MNT_SUIDDIR);
+       OPT_ADD("nosymfollow",  MNT_NOSYMFOLLOW);
+       OPT_ADD("noatime",      MNT_NOATIME);
+#undef OPT_ADD
+
+       sbuf_printf(sb, " 0 0\n");
+
+       return 0;
+}
+
+int
+linprocfs_domounts(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                   struct uio *uio)
+{
+       struct sbuf *sb;
+       int error;
+
+       sb = sbuf_new_auto();
+
+       error = mountlist_scan(linprocfs_domounts_callback, sb, MNTSCAN_FORWARD);
+
+       sbuf_finish(sb);
+       if (error == 0)
+               error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
+       sbuf_delete(sb);
+       return (error);
+}
+
 int
 linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                 struct uio *uio)
 {
         char *ps;
-       char psbuf[512];
+       char psbuf[8192];
+       int cpu;
 
        ps = psbuf;
        ps += ksprintf(ps,
-                     "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n"
+                     "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",
+                     T2J(cpu_time.cp_user),
+                     T2J(cpu_time.cp_nice),
+                     T2J(cpu_time.cp_sys),
+                     T2J(cpu_time.cp_idle));
+
+       for (cpu = 0; cpu < ncpus; cpu++) {
+               ps += ksprintf(ps,
+                     "cpu%d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",
+                     cpu,
+                     T2J(cputime_percpu[cpu].cp_user),
+                     T2J(cputime_percpu[cpu].cp_nice),
+                     T2J(cputime_percpu[cpu].cp_sys),
+                     T2J(cputime_percpu[cpu].cp_idle));                        
+       }
+
+       ps += ksprintf(ps,
                      "disk 0 0 0 0\n"
                      "page %u %u\n"
                      "swap %u %u\n"
                      "intr %u\n"
                      "ctxt %u\n"
                      "btime %ld\n",
-                     T2J(cpu_time.cp_user),
-                     T2J(cpu_time.cp_nice),
-                     T2J(cpu_time.cp_sys /*+ cpu_time[CP_INTR]*/),
-                     T2J(cpu_time.cp_idle),
                      cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
                      cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
                      cpucnt(offsetof(struct vmmeter, v_swappgsin)),
@@ -285,6 +377,7 @@ linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                      cpucnt(offsetof(struct vmmeter, v_intr)),
                      cpucnt(offsetof(struct vmmeter, v_swtch)),
                      boottime.tv_sec);
+
        return (uiomove_frombuf(psbuf, ps - psbuf, uio));
 }
 
@@ -318,11 +411,59 @@ linprocfs_doversion(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        return (uiomove_frombuf(ps, xlen, uio));
 }
 
+#define B2P(x) ((x) >> PAGE_SHIFT)                     /* bytes to pages */
+int
+linprocfs_dostatm(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                   struct uio *uio)
+{
+       char *ps, psbuf[1024];
+       struct kinfo_proc kp;
+
+       fill_kinfo_proc(p, &kp);
+
+       ps = psbuf;
+       ps += ksprintf(ps, "%d", p->p_pid);
+#define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
+       PS_ADD("",      "%ju",  B2P((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize)));
+       PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_rssize);
+       PS_ADD("",      "%ju",  (uintmax_t)0); /* XXX */
+       PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_tsize);
+       PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_dsize);
+       PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_ssize);
+       PS_ADD("",      "%ju",  (uintmax_t)0); /* XXX */
+#undef PS_ADD
+       ps += ksprintf(ps, "\n");
+
+       return (uiomove_frombuf(psbuf, ps - psbuf, uio));
+}
+
+#define P2K(x) ((x) << (PAGE_SHIFT - 10))              /* pages to kbytes */
 int
 linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                     struct uio *uio)
 {
+       vm_map_t map = &p->p_vmspace->vm_map;
+       vm_map_entry_t entry;
+       vm_offset_t start, end;
        char *ps, psbuf[1024];
+       struct kinfo_proc kp;
+
+       fill_kinfo_proc(p, &kp);
+
+       start = 0;
+       end = 0;
+       vm_map_lock_read(map);
+       for (entry = map->header.next; entry != &map->header;
+               entry = entry->next) {
+               if (entry->maptype != VM_MAPTYPE_NORMAL &&
+                   entry->maptype != VM_MAPTYPE_VPAGETABLE) {
+                       continue;
+               }
+               /* Assuming that text is the first entry */
+               start = entry->start;
+               end = entry->end;
+       }
+       vm_map_unlock_read(map);
 
        ps = psbuf;
        ps += ksprintf(ps, "%d", p->p_pid);
@@ -333,27 +474,27 @@ linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        PS_ADD("pgrp",          "%d",   p->p_pgid);
        PS_ADD("session",       "%d",   p->p_session->s_sid);
        PS_ADD("tty",           "%d",   0); /* XXX */
-       PS_ADD("tpgid",         "%d",   0); /* XXX */
+       PS_ADD("tpgid",         "%d",   kp.kp_tpgid); /* XXX */
        PS_ADD("flags",         "%u",   0); /* XXX */
-       PS_ADD("minflt",        "%u",   0); /* XXX */
-       PS_ADD("cminflt",       "%u",   0); /* XXX */
-       PS_ADD("majflt",        "%u",   0); /* XXX */
-       PS_ADD("cminflt",       "%u",   0); /* XXX */
-       PS_ADD("utime",         "%d",   0); /* XXX */
-       PS_ADD("stime",         "%d",   0); /* XXX */
-       PS_ADD("cutime",        "%d",   0); /* XXX */
-       PS_ADD("cstime",        "%d",   0); /* XXX */
-       PS_ADD("counter",       "%d",   0); /* XXX */
+       PS_ADD("minflt",        "%lu",  kp.kp_ru.ru_minflt); /* XXX */
+       PS_ADD("cminflt",       "%lu",  kp.kp_cru.ru_minflt); /* XXX */
+       PS_ADD("majflt",        "%lu",  kp.kp_ru.ru_majflt); /* XXX */
+       PS_ADD("cmajflt",       "%lu",  kp.kp_cru.ru_majflt); /* XXX */
+       PS_ADD("utime",         "%d",   T2J(tvtohz_high(&kp.kp_ru.ru_utime))); /* XXX */
+       PS_ADD("stime",         "%d",   T2J(tvtohz_high(&kp.kp_ru.ru_stime))); /* XXX */
+       PS_ADD("cutime",        "%d",   T2J(tvtohz_high(&kp.kp_cru.ru_utime))); /* XXX */
+       PS_ADD("cstime",        "%d",   T2J(tvtohz_high(&kp.kp_cru.ru_stime))); /* XXX */
        PS_ADD("priority",      "%d",   0); /* XXX */
+       PS_ADD("nice",          "%d",   kp.kp_nice);
        PS_ADD("timeout",       "%u",   0); /* XXX */
        PS_ADD("itrealvalue",   "%u",   0); /* XXX */
-       PS_ADD("starttime",     "%d",   0); /* XXX */
-       PS_ADD("vsize",         "%u",   0); /* XXX */
-       PS_ADD("rss",           "%u",   0); /* XXX */
-       PS_ADD("rlim",          "%u",   0); /* XXX */
-       PS_ADD("startcode",     "%u",   0); /* XXX */
-       PS_ADD("endcode",       "%u",   0); /* XXX */
-       PS_ADD("startstack",    "%u",   0); /* XXX */
+       PS_ADD("starttime",     "%d",   T2J(tvtohz_high(&kp.kp_start))); /* XXX */
+       PS_ADD("vsize",         "%ju",  P2K((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize))); /* XXX: not sure */
+       PS_ADD("rss",           "%ju",  (uintmax_t)kp.kp_vm_rssize); /* XXX */
+       PS_ADD("rlim",          "%lu",  kp.kp_ru.ru_maxrss); /* XXX */
+       PS_ADD("startcode",     "%lu",  start); /* XXX */
+       PS_ADD("endcode",       "%lu",  end); /* XXX */
+       PS_ADD("startstack",    "%lu",  (u_long)p->p_vmspace->vm_minsaddr); /* XXX */
        PS_ADD("kstkesp",       "%u",   0); /* XXX */
        PS_ADD("kstkeip",       "%u",   0); /* XXX */
        PS_ADD("signal",        "%d",   0); /* XXX */
@@ -361,6 +502,12 @@ linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        PS_ADD("sigignore",     "%d",   0); /* XXX */
        PS_ADD("sigcatch",      "%d",   0); /* XXX */
        PS_ADD("wchan",         "%u",   0); /* XXX */
+       PS_ADD("nswap",         "%lu",  kp.kp_ru.ru_nswap); /* XXX */
+       PS_ADD("cnswap",        "%lu",  kp.kp_cru.ru_nswap); /* XXX */
+       PS_ADD("exitsignal",    "%d",   0); /* XXX */
+       PS_ADD("processor",     "%u",   kp.kp_lwp.kl_cpuid); /* XXX */
+       PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
+       PS_ADD("policy",        "%u",   kp.kp_nice); /* XXX */ /* >= 2.5.19 */
 #undef PS_ADD
        ps += ksprintf(ps, "\n");
        
@@ -483,3 +630,199 @@ linprocfs_doloadavg(struct proc *curp, struct proc *p,
        return(uiomove_frombuf(psbuf, ps - psbuf, uio));
 }
 
+int
+linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                  struct uio *uio)
+{
+       struct sbuf *sb;
+       char ifname[16]; /* XXX LINUX_IFNAMSIZ */
+       struct ifnet *ifp;
+       int error;
+
+       sb = sbuf_new_auto();
+
+       sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
+           "Inter-", "   Receive", "  Transmit", " face",
+           "bytes    packets errs drop fifo frame compressed",
+           "bytes    packets errs drop fifo frame compressed");
+
+       crit_enter();
+       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+               linux_ifname(ifp, ifname, sizeof ifname);
+               sbuf_printf(sb, "%6.6s:", ifname);
+               sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
+                   0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+               sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+                   0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+       }
+       crit_exit();
+       sbuf_finish(sb);
+       error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
+       sbuf_delete(sb);
+       return (error);
+}
+
+int
+linprocfs_dodevices(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                  struct uio *uio)
+{
+       return 0;
+}
+
+int
+linprocfs_doosrelease(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                  struct uio *uio)
+{
+       char *osrelease;
+
+       osrelease = linux_get_osrelease(curthread);
+       return(uiomove_frombuf(osrelease, strlen(osrelease)+1, uio));
+}
+
+int
+linprocfs_doostype(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                  struct uio *uio)
+{
+       char *osname;
+
+       osname = linux_get_osname(curthread);
+       return(uiomove_frombuf(osname, strlen(osname)+1, uio));
+}
+
+int
+linprocfs_dopidmax(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+                  struct uio *uio)
+{
+       char buf[32];
+
+       ksnprintf(buf, sizeof(buf), "%d", PID_MAX);
+       return(uiomove_frombuf(buf, strlen(buf)+1, uio));
+       return 0;
+}
+
+int
+linprocfs_domaps(struct proc *curp, struct proc *p, struct pfsnode *pfs,
+            struct uio *uio)
+{
+       int len;
+       int error;
+       vm_map_t map = &p->p_vmspace->vm_map;
+       vm_map_entry_t entry;
+       vm_ooffset_t off = 0;
+       char mebuffer[256];
+       char *name = "", *freename = NULL;
+       struct vnode *vp;
+       struct vattr vat;
+       int major, minor;
+       ino_t ino;
+
+       if (uio->uio_rw != UIO_READ)
+               return (EOPNOTSUPP);
+
+       if (uio->uio_offset != 0)
+               return (0);
+       
+       error = 0;
+       vm_map_lock_read(map);
+       for (entry = map->header.next;
+               ((uio->uio_resid > 0) && (entry != &map->header));
+               entry = entry->next) {
+               vm_object_t obj, tobj, lobj;
+               vm_offset_t ostart;
+               name = "";
+               freename = NULL;
+               ino = 0;
+               if (entry->maptype != VM_MAPTYPE_NORMAL &&
+                   entry->maptype != VM_MAPTYPE_VPAGETABLE) {
+                       continue;
+               }
+               /*
+                * Use map->hint as a poor man's ripout detector.
+                */
+               map->hint = entry;
+               ostart = entry->start;
+               obj = entry->object.vm_object;
+
+               for( lobj = tobj = obj; tobj; tobj = tobj->backing_object)
+                       lobj = tobj;
+
+               if (lobj) {
+                       off = IDX_TO_OFF(lobj->size);
+                       if (lobj->type == OBJT_VNODE) {
+                               vp = lobj->handle;
+                               if (vp)
+                                       vref(vp);
+                       } else {
+                               vp = NULL;
+                       }
+                       
+                       if (vp) {
+                               vn_fullpath(curproc, vp, &name, &freename);
+                               vn_lock(vp, LK_SHARED | LK_RETRY);
+                               VOP_GETATTR(vp, &vat);
+                               ino = vat.va_fileid;
+                               major = vat.va_rmajor;
+                               minor = vat.va_rminor;
+                               vput(vp);
+                       }
+               }
+               if (freename == NULL) {
+                       if (entry->eflags & MAP_ENTRY_STACK)
+                               name = "[stack]";
+               }
+
+               /*
+                * format:
+                *  start-end access offset major:minor inode [.text file]
+                */
+               ksnprintf(mebuffer, sizeof(mebuffer),
+                   "%08lx-%08lx %s%s%s%s %08llx %02x:%02x %llu%s%s\n",
+                   (u_long)entry->start, (u_long)entry->end,
+                   (entry->protection & VM_PROT_READ)?"r":"-",
+                   (entry->protection & VM_PROT_WRITE)?"w":"-",
+                   (entry->protection & VM_PROT_EXECUTE)?"x":"-",
+                   "p",
+                   off,        /* offset */
+                   0,          /* major */
+                   0,          /* minor */
+                   ino,        /* inode */
+                   *name ? "     " : "",
+                   name);
+
+               if (freename)
+                       kfree(freename, M_TEMP);
+
+               len = strlen(mebuffer);
+               if (len > uio->uio_resid) {
+                       error = EFBIG;
+                       break;
+               }
+
+               /*
+                * We cannot safely hold the map locked while accessing
+                * userspace as a VM fault might recurse the locked map.
+                */
+               vm_map_unlock_read(map);
+               error = uiomove(mebuffer, len, uio);
+               vm_map_lock_read(map);
+               if (error)
+                       break;
+
+               /*
+                * We use map->hint as a poor man's ripout detector.  If
+                * it does not match the entry we set it to prior to
+                * unlocking the map the entry MIGHT now be stale.  In
+                * this case we do an expensive lookup to find our place
+                * in the iteration again.
+                */
+               if (map->hint != entry) {
+                       vm_map_entry_t reentry;
+               
+                       vm_map_lookup_entry(map, ostart, &reentry);
+                       entry = reentry;
+               }
+       }
+       vm_map_unlock_read(map);
+
+       return error;
+}
index 2058332..ccda25d 100644 (file)
@@ -147,11 +147,15 @@ loop:
 
        switch (pfs_type) {
        case Proot:     /* /proc = dr-xr-xr-x */
+               vsetflags(vp, VROOT);
+               /* fallthrough */
+       case Pnet:
+       case Psys:
+       case Psyskernel:
                pfs->pfs_mode = (VREAD|VEXEC) |
                                (VREAD|VEXEC) >> 3 |
                                (VREAD|VEXEC) >> 6;
                vp->v_type = VDIR;
-               vsetflags(vp, VROOT);
                break;
 
        case Pself:     /* /proc/self = lr--r--r-- */
@@ -169,6 +173,9 @@ loop:
                break;
 
        case Pexe:
+       case Pcwd:
+       case Pprocroot:
+       case Pfd:
                pfs->pfs_mode = (VREAD|VEXEC) |
                                (VREAD|VEXEC) >> 3 |
                                (VREAD|VEXEC) >> 6;
@@ -183,14 +190,23 @@ loop:
 
        case Pprocstat:
        case Pprocstatus:
+       case Pcmdline:
+       case Penviron:
+       case Pstatm:
                /* fallthrough */
-               
+       case Pmaps:
        case Pmeminfo:
        case Pcpuinfo:
+       case Pmounts:
        case Pstat:
        case Puptime:
        case Pversion:
        case Ploadavg:
+       case Pdevices:
+       case Pnetdev:
+       case Posrelease:
+       case Postype:
+       case Ppidmax:
                pfs->pfs_mode = (VREAD) |
                                (VREAD >> 3) |
                                (VREAD >> 6);
@@ -267,7 +283,6 @@ linprocfs_rw(struct vop_read_args *ap)
                tsleep(&pfs->pfs_lockowner, 0, "pfslck", 0);
        }
        pfs->pfs_lockowner = curthread;
-
        switch (pfs->pfs_type) {
        case Pmem:
                rtval = procfs_domem(curp, lp, pfs, uio);
@@ -284,6 +299,9 @@ linprocfs_rw(struct vop_read_args *ap)
        case Pcpuinfo:
                rtval = linprocfs_docpuinfo(curp, p, pfs, uio);
                break;
+       case Pmounts:
+               rtval = linprocfs_domounts(curp, p, pfs, uio);
+               break;
        case Pstat:
                rtval = linprocfs_dostat(curp, p, pfs, uio);
                break;
@@ -296,6 +314,27 @@ linprocfs_rw(struct vop_read_args *ap)
        case Ploadavg:
                rtval = linprocfs_doloadavg(curp, p, pfs, uio);
                break;
+       case Pnetdev:
+               rtval = linprocfs_donetdev(curp, p, pfs, uio);
+               break;
+       case Pdevices:
+               rtval = linprocfs_dodevices(curp, p, pfs, uio);
+               break;
+       case Posrelease:
+               rtval = linprocfs_doosrelease(curp, p, pfs, uio);
+               break;
+       case Postype:
+               rtval = linprocfs_doostype(curp, p, pfs, uio);
+               break;
+       case Ppidmax:
+               rtval = linprocfs_dopidmax(curp, p, pfs, uio);
+               break;
+       case Pmaps:
+               rtval = linprocfs_domaps(curp, p, pfs, uio);
+               break;
+       case Pstatm:
+               rtval = linprocfs_dostatm(curp, p, pfs, uio);
+               break;
        default:
                rtval = EOPNOTSUPP;
                break;
@@ -367,7 +406,7 @@ void
 linprocfs_init(void)
 {
        lwkt_token_init(&pfs_token);
-}
+} 
 
 void
 linprocfs_exit(struct thread *td)
index 14bc703..8f06b90 100644 (file)
@@ -61,6 +61,7 @@
 #include <sys/dirent.h>
 #include <sys/malloc.h>
 #include <sys/reg.h>
+#include <sys/jail.h>
 #include <vm/vm_zone.h>
 #include "linprocfs.h"
 #include <sys/pioctl.h>
@@ -86,6 +87,9 @@ static int    linprocfs_setattr (struct vop_setattr_args *);
 
 static int     linprocfs_readdir_proc(struct vop_readdir_args *);
 static int     linprocfs_readdir_root(struct vop_readdir_args *);
+static int     linprocfs_readdir_net(struct vop_readdir_args *ap);
+static int     linprocfs_readdir_sys(struct vop_readdir_args *ap);
+static int     linprocfs_readdir_syskernel(struct vop_readdir_args *ap);
 
 /*
  * procfs vnode operations.
@@ -136,9 +140,20 @@ static struct proc_target {
        { DT_DIR, N("."),       Pproc,          NULL },
        { DT_DIR, N(".."),      Proot,          NULL },
        { DT_REG, N("mem"),     Pmem,           NULL },
+
        { DT_LNK, N("exe"),     Pexe,           NULL },
+       { DT_LNK, N("cwd"),     Pcwd,           NULL },
+       { DT_LNK, N("root"),    Pprocroot,      NULL },
+       { DT_LNK, N("fd"),      Pfd,            NULL },
+
        { DT_REG, N("stat"),    Pprocstat,      NULL },
        { DT_REG, N("status"),  Pprocstatus,    NULL },
+       { DT_REG, N("maps"),    Pmaps,          NULL },
+       { DT_REG, N("statm"),   Pstatm,         NULL },
+#if 0
+       { DT_REG, N("cmdline"), Pcmdline,       NULL },
+       { DT_REG, N("environ"), Penviron,       NULL },
+#endif
 #undef N
 };
 static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
@@ -466,6 +481,9 @@ linprocfs_getattr(struct vop_getattr_args *ap)
 
        switch (pfs->pfs_type) {
        case Proot:
+       case Pnet:
+       case Psys:
+       case Psyskernel:
                /*
                 * Set nlink to 1 to tell fts(3) we don't actually know.
                 */
@@ -491,7 +509,36 @@ linprocfs_getattr(struct vop_getattr_args *ap)
 
        case Pexe: {
                char *fullpath, *freepath;
-               error = vn_fullpath(procp, NULL, &fullpath, &freepath);
+               error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath);
+               /* error = vn_fullpath(procp, NULL, &fullpath, &freepath); */
+               if (error == 0) {
+                       vap->va_size = strlen(fullpath);
+                       kfree(freepath, M_TEMP);
+               } else {
+                       vap->va_size = sizeof("unknown") - 1;
+                       error = 0;
+               }
+               vap->va_bytes = vap->va_size;
+               break;
+       }
+       case Pcwd: {
+               char *fullpath, *freepath;
+               error = cache_fullpath(procp, &procp->p_fd->fd_ncdir, &fullpath, &freepath);
+               if (error == 0) {
+                       vap->va_size = strlen(fullpath);
+                       kfree(freepath, M_TEMP);
+               } else {
+                       vap->va_size = sizeof("unknown") - 1;
+                       error = 0;
+               }
+               vap->va_bytes = vap->va_size;
+               break;
+       }
+       case Pprocroot: {
+               struct nchandle *nchp;
+               char *fullpath, *freepath;
+               nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
+               error = cache_fullpath(procp, nchp, &fullpath, &freepath);
                if (error == 0) {
                        vap->va_size = strlen(fullpath);
                        kfree(freepath, M_TEMP);
@@ -502,13 +549,30 @@ linprocfs_getattr(struct vop_getattr_args *ap)
                vap->va_bytes = vap->va_size;
                break;
        }
+       case Pfd: {
+               if (procp == curproc) {
+                       vap->va_size = sizeof("/dev/fd") - 1;
+                       error = 0;      
+               } else {
+                       vap->va_size = sizeof("unknown") - 1;
+                       error = 0;
+               }
+               vap->va_bytes = vap->va_size;
+               break;
+       }
 
        case Pmeminfo:
        case Pcpuinfo:
+       case Pmounts:
        case Pstat:
        case Puptime:
        case Pversion:
        case Ploadavg:
+       case Pnetdev:
+       case Pdevices:
+       case Posrelease:
+       case Postype:
+       case Ppidmax:
                vap->va_bytes = vap->va_size = 0;
                vap->va_uid = 0;
                vap->va_gid = 0;
@@ -528,6 +592,10 @@ linprocfs_getattr(struct vop_getattr_args *ap)
 
        case Pprocstat:
        case Pprocstatus:
+       case Pcmdline:
+       case Penviron:
+       case Pmaps:
+       case Pstatm:
                vap->va_bytes = vap->va_size = 0;
                /* uid, gid are already set */
                break;
@@ -651,6 +719,50 @@ linprocfs_lookup(struct vop_old_lookup_args *ap)
 
        pfs = VTOPFS(dvp);
        switch (pfs->pfs_type) {
+       case Psys:
+               if (cnp->cn_flags & CNP_ISDOTDOT) {
+                       error = linprocfs_root(dvp->v_mount, vpp);
+                       goto out;
+               }
+               if (CNEQ(cnp, "kernel", 6)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Psyskernel);
+                       goto out;
+               }               
+               break;
+       case Pnet:
+               if (cnp->cn_flags & CNP_ISDOTDOT) {
+                       error = linprocfs_root(dvp->v_mount, vpp);
+                       goto out;
+               }
+               if (CNEQ(cnp, "dev", 3)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pnetdev);
+                       goto out;
+               }               
+               break;
+       case Psyskernel:
+               if (cnp->cn_flags & CNP_ISDOTDOT) {
+                       /* XXX: this is wrong, wrong, wrong. */
+                       error = linprocfs_root(dvp->v_mount, vpp);
+                       goto out;
+               }
+               if (CNEQ(cnp, "osrelease", 9)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Posrelease);
+                       goto out;
+               }
+               if (CNEQ(cnp, "ostype", 6)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Postype);
+                       goto out;
+               }
+               if (CNEQ(cnp, "pid_max", 7)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ppidmax);
+                       goto out;
+               }
+               if (CNEQ(cnp, "version", 7)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pversion);
+                       goto out;
+               }
+               break;
+               
        case Proot:
                if (cnp->cn_flags & CNP_ISDOTDOT)
                        return (EIO);
@@ -667,6 +779,10 @@ linprocfs_lookup(struct vop_old_lookup_args *ap)
                        error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pcpuinfo);
                        goto out;
                }
+               if (CNEQ(cnp, "mounts", 6)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pmounts);
+                       goto out;
+               }
                if (CNEQ(cnp, "stat", 4)) {
                        error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pstat);
                        goto out;
@@ -683,6 +799,14 @@ linprocfs_lookup(struct vop_old_lookup_args *ap)
                        error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Ploadavg);
                        goto out;
                }
+               if (CNEQ(cnp, "net", 3)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Pnet);
+                       goto out;
+               }
+               if (CNEQ(cnp, "sys", 3)) {
+                       error = linprocfs_allocvp(dvp->v_mount, vpp, 0, Psys);
+                       goto out;
+               }
 
                pid = atopid(pname, cnp->cn_namelen);
                if (pid == NO_PID)
@@ -807,6 +931,15 @@ linprocfs_readdir(struct vop_readdir_args *ap)
                 */
                error = linprocfs_readdir_root(ap);
                break;
+       case Pnet:
+               error = linprocfs_readdir_net(ap);
+               break;
+       case Psys:
+               error = linprocfs_readdir_sys(ap);
+               break;
+       case Psyskernel:
+               error = linprocfs_readdir_syskernel(ap);
+               break;
        default:
                error = ENOTDIR;
                break;
@@ -870,7 +1003,7 @@ linprocfs_readdir_root(struct vop_readdir_args *ap)
 {
        struct linprocfs_readdir_root_info info;
        struct uio *uio = ap->a_uio;
-       int res;
+       int res = 0;
 
        info.error = 0;
        info.i = uio->uio_offset;
@@ -878,7 +1011,7 @@ linprocfs_readdir_root(struct vop_readdir_args *ap)
        info.uio = uio;
        info.cred = ap->a_cred;
 
-       while (info.pcnt < 9) {
+       while (info.pcnt < 12) {
                res = linprocfs_readdir_root_callback(NULL, &info);
                if (res < 0)
                        break;
@@ -964,7 +1097,32 @@ linprocfs_readdir_root_callback(struct proc *p, void *data)
                d_name = "loadavg";
                d_type = DT_REG;
                break;
-
+       case 9:
+               d_ino = PROCFS_FILENO(0, Pnet);
+               d_namlen = 3;
+               d_name = "net";
+               d_type = DT_DIR;
+               break;
+       case 10:
+               d_ino = PROCFS_FILENO(0, Psys);
+               d_namlen = 3;
+               d_name = "sys";
+               d_type = DT_DIR;
+               break;
+       case 11:
+               d_ino = PROCFS_FILENO(0, Pmounts);
+               d_namlen = 6;
+               d_name = "mounts";
+               d_type = DT_DIR;
+               break;
+#if 0
+       case 11:
+               d_ino = PROCFS_FILENO(0, Pdevices);
+               d_namlen = 7;
+               d_name = "devices";
+               d_type = DT_REG;
+               break;          
+#endif
        default:
                /*
                 * Ignore processes that aren't in our prison
@@ -1014,6 +1172,292 @@ linprocfs_readdir_root_callback(struct proc *p, void *data)
        return(0);
 }
 
+/*
+ * Scan the root directory by scanning all process
+ */
+static int linprocfs_readdir_net_callback(struct proc *p, void *data);
+
+static int
+linprocfs_readdir_net(struct vop_readdir_args *ap)
+{
+       struct linprocfs_readdir_root_info info;
+       struct uio *uio = ap->a_uio;
+       int res;
+
+       info.error = 0;
+       info.i = uio->uio_offset;
+       info.pcnt = 0;
+       info.uio = uio;
+       info.cred = ap->a_cred;
+
+       while (info.pcnt < 3) {
+               res = linprocfs_readdir_net_callback(NULL, &info);
+               if (res < 0)
+                       break;
+       }
+
+       uio->uio_offset = info.i;
+       return(info.error);
+}
+
+static int
+linprocfs_readdir_net_callback(struct proc *p, void *data)
+{
+       struct linprocfs_readdir_root_info *info = data;
+       int retval;
+       struct uio *uio = info->uio;
+       ino_t d_ino;
+       const char *d_name;
+       size_t d_namlen;
+       uint8_t d_type;
+
+       switch (info->pcnt) {
+       case 0:         /* `.' */
+               d_ino = PROCFS_FILENO(0, Pnet);
+               d_name = ".";
+               d_namlen = 1;
+               d_type = DT_DIR;
+               break;
+       case 1:         /* `..' */
+               d_ino = PROCFS_FILENO(0, Proot);
+               d_name = "..";
+               d_namlen = 2;
+               d_type = DT_DIR;
+               break;
+
+       case 2:
+               d_ino = PROCFS_FILENO(0, Pnet);
+               d_namlen = 3;
+               d_name = "dev";
+               d_type = DT_REG;
+               break;
+       default:
+               d_ino = 0;
+               d_namlen = 0;
+               d_name = NULL;
+               d_type = DT_REG;
+               break;
+       }
+
+       /*
+        * Skip processes we have already read
+        */
+       if (info->pcnt < info->i) {
+               ++info->pcnt;
+               return(0);
+       }
+       retval = vop_write_dirent(&info->error, info->uio, 
+                                 d_ino, d_type, d_namlen, d_name);
+       if (retval == 0) {
+               ++info->pcnt;   /* iterate proc candidates scanned */
+               ++info->i;      /* iterate entries written */
+       }
+       if (retval || info->error || uio->uio_resid <= 0)
+               return(-1);
+       return(0);
+}
+
+
+
+
+
+
+
+/*
+ * Scan the root directory by scanning all process
+ */
+static int linprocfs_readdir_sys_callback(struct proc *p, void *data);
+
+static int
+linprocfs_readdir_sys(struct vop_readdir_args *ap)
+{
+       struct linprocfs_readdir_root_info info;
+       struct uio *uio = ap->a_uio;
+       int res;
+
+       info.error = 0;
+       info.i = uio->uio_offset;
+       info.pcnt = 0;
+       info.uio = uio;
+       info.cred = ap->a_cred;
+
+       while (info.pcnt < 3) {
+               res = linprocfs_readdir_sys_callback(NULL, &info);
+               if (res < 0)
+                       break;
+       }
+
+       uio->uio_offset = info.i;
+       return(info.error);
+}
+
+static int
+linprocfs_readdir_sys_callback(struct proc *p, void *data)
+{
+       struct linprocfs_readdir_root_info *info = data;
+       int retval;
+       struct uio *uio = info->uio;
+       ino_t d_ino;
+       const char *d_name;
+       size_t d_namlen;
+       uint8_t d_type;
+
+       switch (info->pcnt) {
+       case 0:         /* `.' */
+               d_ino = PROCFS_FILENO(0, Psys);
+               d_name = ".";
+               d_namlen = 1;
+               d_type = DT_DIR;
+               break;
+       case 1:         /* `..' */
+               d_ino = PROCFS_FILENO(0, Proot);
+               d_name = "..";
+               d_namlen = 2;
+               d_type = DT_DIR;
+               break;
+
+       case 2:
+               d_ino = PROCFS_FILENO(0, Psyskernel);
+               d_namlen = 6;
+               d_name = "kernel";
+               d_type = DT_DIR;
+               break;
+       default:
+               d_ino = 0;
+               d_namlen = 0;
+               d_name = NULL;
+               d_type = DT_REG;
+               break;
+       }
+
+       /*
+        * Skip processes we have already read
+        */
+       if (info->pcnt < info->i) {
+               ++info->pcnt;
+               return(0);
+       }
+       retval = vop_write_dirent(&info->error, info->uio, 
+                                 d_ino, d_type, d_namlen, d_name);
+       if (retval == 0) {
+               ++info->pcnt;   /* iterate proc candidates scanned */
+               ++info->i;      /* iterate entries written */
+       }
+       if (retval || info->error || uio->uio_resid <= 0)
+               return(-1);
+       return(0);
+}
+
+
+
+
+
+/*
+ * Scan the root directory by scanning all process
+ */
+static int linprocfs_readdir_syskernel_callback(struct proc *p, void *data);
+
+static int
+linprocfs_readdir_syskernel(struct vop_readdir_args *ap)
+{
+       struct linprocfs_readdir_root_info info;
+       struct uio *uio = ap->a_uio;
+       int res;
+
+       info.error = 0;
+       info.i = uio->uio_offset;
+       info.pcnt = 0;
+       info.uio = uio;
+       info.cred = ap->a_cred;
+
+       while (info.pcnt < 6) {
+               res = linprocfs_readdir_syskernel_callback(NULL, &info);
+               if (res < 0)
+                       break;
+       }
+
+       uio->uio_offset = info.i;
+       return(info.error);
+}
+
+static int
+linprocfs_readdir_syskernel_callback(struct proc *p, void *data)
+{
+       struct linprocfs_readdir_root_info *info = data;
+       int retval;
+       struct uio *uio = info->uio;
+       ino_t d_ino;
+       const char *d_name;
+       size_t d_namlen;
+       uint8_t d_type;
+
+       switch (info->pcnt) {
+       case 0:         /* `.' */
+               d_ino = PROCFS_FILENO(0, Psyskernel);
+               d_name = ".";
+               d_namlen = 1;
+               d_type = DT_DIR;
+               break;
+       case 1:         /* `..' */
+               d_ino = PROCFS_FILENO(0, Psys);
+               d_name = "..";
+               d_namlen = 2;
+               d_type = DT_DIR;
+               break;
+
+       case 2:
+               d_ino = PROCFS_FILENO(0, Posrelease);
+               d_namlen = 9;
+               d_name = "osrelease";
+               d_type = DT_REG;
+               break;
+
+       case 3:
+               d_ino = PROCFS_FILENO(0, Postype);
+               d_namlen = 4;
+               d_name = "ostype";
+               d_type = DT_REG;
+               break;
+
+       case 4:
+               d_ino = PROCFS_FILENO(0, Pversion);
+               d_namlen = 7;
+               d_name = "version";
+               d_type = DT_REG;
+               break;
+
+       case 5:
+               d_ino = PROCFS_FILENO(0, Ppidmax);
+               d_namlen = 7;
+               d_name = "pid_max";
+               d_type = DT_REG;
+               break;
+       default:
+               d_ino = 0;
+               d_namlen = 0;
+               d_name = NULL;
+               d_type = DT_REG;
+               break;
+       }
+
+       /*
+        * Skip processes we have already read
+        */
+       if (info->pcnt < info->i) {
+               ++info->pcnt;
+               return(0);
+       }
+       retval = vop_write_dirent(&info->error, info->uio, 
+                                 d_ino, d_type, d_namlen, d_name);
+       if (retval == 0) {
+               ++info->pcnt;   /* iterate proc candidates scanned */
+               ++info->i;      /* iterate entries written */
+       }
+       if (retval || info->error || uio->uio_resid <= 0)
+               return(-1);
+       return(0);
+}
+
 /*
  * readlink reads the link of `self' or `exe'
  */
@@ -1023,6 +1467,7 @@ linprocfs_readlink(struct vop_readlink_args *ap)
        char buf[16];           /* should be enough */
        struct proc *procp;
        struct vnode *vp = ap->a_vp;
+       struct nchandle *nchp;
        struct pfsnode *pfs = VTOPFS(vp);
        char *fullpath, *freepath;
        int error, len;
@@ -1047,13 +1492,61 @@ linprocfs_readlink(struct vop_readlink_args *ap)
                        return (uiomove("unknown", sizeof("unknown") - 1,
                            ap->a_uio));
                }
-               error = vn_fullpath(procp, NULL, &fullpath, &freepath);
+               error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath);
                if (error != 0)
                        return (uiomove("unknown", sizeof("unknown") - 1,
                            ap->a_uio));
                error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
                kfree(freepath, M_TEMP);
                return (error);
+       case Pcwd:
+               procp = PFIND(pfs->pfs_pid);
+               if (procp == NULL || procp->p_ucred == NULL) {
+                       kprintf("linprocfs_readlink: pid %d disappeared\n",
+                           pfs->pfs_pid);
+                       return (uiomove("unknown", sizeof("unknown") - 1,
+                           ap->a_uio));
+               }
+               error = cache_fullpath(procp, &procp->p_fd->fd_ncdir, &fullpath, &freepath);
+               if (error != 0)
+                       return (uiomove("unknown", sizeof("unknown") - 1,
+                           ap->a_uio));
+               error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
+               kfree(freepath, M_TEMP);
+               return (error);
+       case Pprocroot:
+               procp = PFIND(pfs->pfs_pid);
+               if (procp == NULL || procp->p_ucred == NULL) {
+                       kprintf("linprocfs_readlink: pid %d disappeared\n",
+                           pfs->pfs_pid);
+                       return (uiomove("unknown", sizeof("unknown") - 1,
+                           ap->a_uio));
+               }
+               nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
+               error = cache_fullpath(procp, nchp, &fullpath, &freepath);
+               if (error != 0)
+                       return (uiomove("unknown", sizeof("unknown") - 1,
+                           ap->a_uio));
+               error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
+               kfree(freepath, M_TEMP);
+               return (error);
+       case Pfd:
+               procp = PFIND(pfs->pfs_pid);
+               if (procp == NULL || procp->p_ucred == NULL) {
+                       kprintf("linprocfs_readlink: pid %d disappeared\n",
+                           pfs->pfs_pid);
+                       return (uiomove("unknown", sizeof("unknown") - 1,
+                           ap->a_uio));
+               }
+               if (procp == curproc) {
+                       return (uiomove("/dev/fd", sizeof("/dev/fd") - 1,
+                           ap->a_uio));
+               } else {
+                       return (uiomove("unknown", sizeof("unknown") - 1,
+                           ap->a_uio));
+               }
+               /* notreached */
+               break;
        default:
                return (EINVAL);
        }
index 4386f73..2e9a238 100644 (file)
@@ -44,10 +44,17 @@ extern u_char linux_debug_map[];
 #define ARGS(nm, fmt)  "linux(%ld): "#nm"("fmt")\n", (long)(curthread->td_proc ? curthread->td_proc->p_pid : -1)
 #define LMSG(fmt)      "linux(%ld): "fmt"\n", (long)(curthread->td_proc ? curthread->td_proc->p_pid : -1)
 
+#if 0
+#define LINUX_DEBUG    1
+#endif
+
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_LINUX);
 #endif
 
+#define        PTRIN(v)        (void *)(v)
+#define        PTROUT(v)       (l_uintptr_t)(v)
+
 /*
  * Provide a separate set of types for the Linux types.
  */
@@ -60,6 +67,7 @@ typedef uint32_t      l_ulong;
 typedef uint64_t       l_ulonglong;
 typedef unsigned short l_ushort;
 
+typedef l_ulong                l_uintptr_t;
 typedef char           *l_caddr_t;
 typedef l_long         l_clock_t;
 typedef l_int          l_daddr_t;
@@ -77,6 +85,8 @@ typedef l_long                l_suseconds_t;
 typedef l_long         l_time_t;
 typedef l_uint         l_uid_t;
 typedef l_ushort       l_uid16_t;
+typedef l_int          l_timer_t;
+typedef l_int          l_mqd_t;
 
 typedef struct {
        l_int           val[2];
@@ -143,8 +153,8 @@ struct l_rlimit {
  * stat family of syscalls
  */
 struct l_timespec {
-       l_ulong         tv_sec;
-       l_ulong         tv_nsec;
+       l_time_t        tv_sec;
+       l_long          tv_nsec;
 };
 
 struct l_newstat {
@@ -187,6 +197,19 @@ struct l_stat64 {
        l_ulonglong     st_ino;
 };
 
+struct l_statfs64 {
+        l_int           f_type;
+        l_int           f_bsize;
+        uint64_t        f_blocks;
+        uint64_t        f_bfree;
+        uint64_t        f_bavail;
+        uint64_t        f_files;
+        uint64_t        f_ffree;
+        l_fsid_t        f_fsid;
+        l_int           f_namelen;
+        l_int           f_spare[6];
+};
+
 struct l_new_utsname {
        char    sysname[LINUX_MAX_UTSNAME];
        char    nodename[LINUX_MAX_UTSNAME];
@@ -231,7 +254,7 @@ struct l_new_utsname {
 #define        LINUX_SIGIO             29
 #define        LINUX_SIGPOLL           LINUX_SIGIO
 #define        LINUX_SIGPWR            30
-#define        LINUX_SIGUNUSED         31
+#define        LINUX_SIGSYS            31
 
 #define        LINUX_SIGTBLSZ          31
 #define        LINUX_NSIG_WORDS        2
@@ -596,6 +619,13 @@ union l_semun {
 #define        LINUX_SO_NO_CHECK       11
 #define        LINUX_SO_PRIORITY       12
 #define        LINUX_SO_LINGER         13
+#define        LINUX_SO_PEERCRED       17
+#define        LINUX_SO_RCVLOWAT       18
+#define        LINUX_SO_SNDLOWAT       19
+#define        LINUX_SO_RCVTIMEO       20
+#define        LINUX_SO_SNDTIMEO       21
+#define        LINUX_SO_TIMESTAMP      29
+#define        LINUX_SO_ACCEPTCONN     30
 
 #define        LINUX_IP_TOS            1
 #define        LINUX_IP_TTL            2
@@ -638,6 +668,7 @@ struct l_ifreq {
                struct l_sockaddr       ifru_hwaddr;
                l_short         ifru_flags[1];
                l_int           ifru_metric;
+               l_int           ifru_ivalue;
                l_int           ifru_mtu;
                struct l_ifmap  ifru_map;
                char            ifru_slave[LINUX_IFNAMSIZ];
@@ -647,6 +678,8 @@ struct l_ifreq {
 
 #define        ifr_name        ifr_ifrn.ifrn_name      /* interface name */
 #define        ifr_hwaddr      ifr_ifru.ifru_hwaddr    /* MAC address */
+#define        ifr_ifindex     ifr_ifru.ifru_ivalue    /* Interface index */
+#define        ifr_ifmetric    ifr_ifru.ifru_metric    /* Interface index */
 
 /*
  * poll()
@@ -669,4 +702,119 @@ struct l_pollfd {
        l_short         revents;
 };
 
+struct l_user_desc {
+       l_uint          entry_number;
+       l_uint          base_addr;
+       l_uint          limit;
+       l_uint          seg_32bit:1;
+       l_uint          contents:2;
+       l_uint          read_exec_only:1;
+       l_uint          limit_in_pages:1;
+       l_uint          seg_not_present:1;
+       l_uint          useable:1;
+};
+
+struct l_desc_struct {
+       unsigned long   a, b;
+};
+
+
+#define        LINUX_LOWERWORD 0x0000ffff
+
+/*
+ * Macros which does the same thing as those in Linux include/asm-um/ldt-i386.h.
+ * These convert Linux user space descriptor to machine one.
+ */
+#define        LINUX_LDT_entry_a(info)                                 \
+       ((((info)->base_addr & LINUX_LOWERWORD) << 16) |        \
+       ((info)->limit & LINUX_LOWERWORD))
+
+#define        LINUX_ENTRY_B_READ_EXEC_ONLY    9
+#define        LINUX_ENTRY_B_CONTENTS          10
+#define        LINUX_ENTRY_B_SEG_NOT_PRESENT   15
+#define        LINUX_ENTRY_B_BASE_ADDR         16
+#define        LINUX_ENTRY_B_USEABLE           20
+#define        LINUX_ENTRY_B_SEG32BIT          22
+#define        LINUX_ENTRY_B_LIMIT             23
+
+#define        LINUX_LDT_entry_b(info)                                                 \
+       (((info)->base_addr & 0xff000000) |                                     \
+       ((info)->limit & 0xf0000) |                                             \
+       ((info)->contents << LINUX_ENTRY_B_CONTENTS) |                          \
+       (((info)->seg_not_present == 0) << LINUX_ENTRY_B_SEG_NOT_PRESENT) |     \
+       (((info)->base_addr & 0x00ff0000) >> LINUX_ENTRY_B_BASE_ADDR) |         \
+       (((info)->read_exec_only == 0) << LINUX_ENTRY_B_READ_EXEC_ONLY) |       \
+       ((info)->seg_32bit << LINUX_ENTRY_B_SEG32BIT) |                         \
+       ((info)->useable << LINUX_ENTRY_B_USEABLE) |                            \
+       ((info)->limit_in_pages << LINUX_ENTRY_B_LIMIT) | 0x7000)
+
+#define        LINUX_LDT_empty(info)           \
+       ((info)->base_addr == 0 &&      \
+       (info)->limit == 0 &&           \
+       (info)->contents == 0 &&        \
+       (info)->seg_not_present == 1 && \
+       (info)->read_exec_only == 1 &&  \
+       (info)->seg_32bit == 0 &&       \
+       (info)->limit_in_pages == 0 &&  \
+       (info)->useable == 0)
+
+/*
+ * Macros for converting segments.
+ * They do the same as those in arch/i386/kernel/process.c in Linux.
+ */
+#define        LINUX_GET_BASE(desc)                            \
+       ((((desc)->a >> 16) & LINUX_LOWERWORD) |        \
+       (((desc)->b << 16) & 0x00ff0000) |              \
+       ((desc)->b & 0xff000000))
+
+#define        LINUX_GET_LIMIT(desc)                   \
+       (((desc)->a & LINUX_LOWERWORD) |        \
+       ((desc)->b & 0xf0000))
+
+#define        LINUX_GET_32BIT(desc)           \
+       (((desc)->b >> LINUX_ENTRY_B_SEG32BIT) & 1)
+#define        LINUX_GET_CONTENTS(desc)        \
+       (((desc)->b >> LINUX_ENTRY_B_CONTENTS) & 3)
+#define        LINUX_GET_WRITABLE(desc)        \
+       (((desc)->b >> LINUX_ENTRY_B_READ_EXEC_ONLY) & 1)
+#define        LINUX_GET_LIMIT_PAGES(desc)     \
+       (((desc)->b >> LINUX_ENTRY_B_LIMIT) & 1)
+#define        LINUX_GET_PRESENT(desc)         \
+       (((desc)->b >> LINUX_ENTRY_B_SEG_NOT_PRESENT) & 1)
+#define        LINUX_GET_USEABLE(desc)         \
+       (((desc)->b >> LINUX_ENTRY_B_USEABLE) & 1)
+
+#define        LINUX_CLOCK_REALTIME            0
+#define        LINUX_CLOCK_MONOTONIC           1
+#define        LINUX_CLOCK_PROCESS_CPUTIME_ID  2
+#define        LINUX_CLOCK_THREAD_CPUTIME_ID   3
+#define        LINUX_CLOCK_REALTIME_HR         4
+#define        LINUX_CLOCK_MONOTONIC_HR        5
+
+#define        LINUX_CLONE_VM                  0x00000100
+#define        LINUX_CLONE_FS                  0x00000200
+#define        LINUX_CLONE_FILES               0x00000400
+#define        LINUX_CLONE_SIGHAND             0x00000800
+#define        LINUX_CLONE_PID                 0x00001000      /* No longer exist in Linux */
+#define        LINUX_CLONE_VFORK               0x00004000
+#define        LINUX_CLONE_PARENT              0x00008000
+#define        LINUX_CLONE_THREAD              0x00010000
+#define        LINUX_CLONE_SETTLS              0x00080000
+#define        LINUX_CLONE_PARENT_SETTID       0x00100000
+#define        LINUX_CLONE_CHILD_CLEARTID      0x00200000
+#define        LINUX_CLONE_CHILD_SETTID        0x01000000
+
+#define        LINUX_THREADING_FLAGS                                   \
+       (LINUX_CLONE_VM | LINUX_CLONE_FS | LINUX_CLONE_FILES |  \
+       LINUX_CLONE_SIGHAND | LINUX_CLONE_THREAD)
+
+#define        LINUX_AT_FDCWD                  -100
+#define        LINUX_AT_SYMLINK_NOFOLLOW       0x100
+#define        LINUX_AT_REMOVEDIR              0x200
+
+#define LINUX_MREMAP_MAYMOVE    1
+#define LINUX_MREMAP_FIXED      2
+
+#define LINUX_UTIME_NOW (-1)
+#define LINUX_UTIME_OMIT (-2)
 #endif /* !_EMULATION_LINUX_ARCH_LINUX_H_ */
index 7c8f8c9..c3dd683 100644 (file)
@@ -69,8 +69,8 @@ DUMMY(setfsuid);
 DUMMY(setfsgid);
 DUMMY(pivot_root);
 DUMMY(mincore);
-DUMMY(madvise);
 DUMMY(fadvise64);
+DUMMY(statfs64);
 
 #define DUMMY_XATTR(s)                                         \
 int                                                            \
index 481694b..9a85b1f 100644 (file)
@@ -12,3 +12,4 @@ ASSYM(LINUX_SC_GS, offsetof(struct l_sigcontext, sc_gs));
 ASSYM(LINUX_SC_EFLAGS, offsetof(struct l_sigcontext, sc_eflags));
 ASSYM(LINUX_RT_SIGF_HANDLER, offsetof(struct l_rt_sigframe, sf_handler));
 ASSYM(LINUX_RT_SIGF_UC, offsetof(struct l_rt_sigframe, sf_sc));
+ASSYM(LINUX_RT_SIGF_SC, offsetof(struct l_ucontext, uc_mcontext));
index 7530681..1f20d9c 100644 (file)
@@ -8,7 +8,7 @@
 NON_GPROF_ENTRY(linux_sigcode)
        call    *LINUX_SIGF_HANDLER(%esp)
        leal    LINUX_SIGF_SC(%esp),%ebx        /* linux scp */
-       movw    LINUX_SC_GS(%ebx),%gs
+       mov     LINUX_SC_GS(%ebx),%gs
        movl    %esp, %ebx                      /* pass sigframe */
        push    %eax                            /* fake ret addr */
        movl    $LINUX_SYS_linux_sigreturn,%eax /* linux_sigreturn() */
@@ -19,7 +19,8 @@ NON_GPROF_ENTRY(linux_sigcode)
 linux_rt_sigcode:
        call    *LINUX_RT_SIGF_HANDLER(%esp)
        leal    LINUX_RT_SIGF_UC(%esp),%ebx     /* linux ucp */
-       movw    LINUX_SC_GS(%ebx),%gs
+       leal    LINUX_RT_SIGF_SC(%ebx),%ecx     /* linux sigcontext */
+       mov     LINUX_SC_GS(%ecx),%gs
        push    %eax                            /* fake ret addr */
        movl    $LINUX_SYS_linux_rt_sigreturn,%eax   /* linux_rt_sigreturn() */
        int     $0x80                           /* enter kernel with args */
index e2edbaf..af6b1ee 100644 (file)
@@ -40,7 +40,9 @@
 #include <sys/priv.h>
 #include <sys/resource.h>
 #include <sys/resourcevar.h>
+#include <sys/ptrace.h>
 #include <sys/sysproto.h>
+#include <sys/thread2.h>
 #include <sys/unistd.h>
 #include <sys/wait.h>
 
@@ -60,6 +62,7 @@
 #include "../linux_ipc.h"
 #include "../linux_signal.h"
 #include "../linux_util.h"
+#include "../linux_emuldata.h"
 
 struct l_descriptor {
        l_uint          entry_number;
@@ -139,8 +142,11 @@ sys_linux_execve(struct linux_execve_args *args)
         * Linux will register %edx as an atexit function and we must be
         * sure to set it to 0.  XXX
         */
-       if (error == 0)
+       if (error == 0) {
                args->sysmsg_result64 = 0;
+               if (curproc->p_sysent == &elf_linux_sysvec)
+                       error = emuldata_init(curproc, NULL, 0);
+       }
 
        exec_free_args(&exec_args);
        linux_free_path(&path);
@@ -225,6 +231,10 @@ sys_linux_ipc(struct linux_ipc_args *args)
 
                a.msqid = args->arg1;
                a.msgsz = args->arg2;
+               if (a.msgsz < 0) {
+                       error = EINVAL;
+                       break;
+               }
                a.msgflg = args->arg3;
                a.sysmsg_lresult = 0;
                if ((args->what >> 16) == 0) {
@@ -356,35 +366,80 @@ sys_linux_old_select(struct linux_old_select_args *args)
 int
 sys_linux_fork(struct linux_fork_args *args)
 {
+       struct lwp *lp = curthread->td_lwp;
+       struct proc *p2;
        int error;
 
-#ifdef DEBUG
-       if (ldebug(fork))
-               kprintf(ARGS(fork, ""));
-#endif
+       get_mplock();
+       error = fork1(lp, RFFDG | RFPROC | RFPGLOCK, &p2);
+       if (error == 0) {
+               emuldata_init(curproc, p2, 0);
 
-       if ((error = sys_fork((struct fork_args *)args)) != 0)
-               return (error);
+               start_forked_proc(lp, p2);
+               args->sysmsg_fds[0] = p2->p_pid;
+               args->sysmsg_fds[1] = 0;
+       }
+       rel_mplock();
 
+       /* Are we the child? */
        if (args->sysmsg_iresult == 1)
                args->sysmsg_iresult = 0;
-       return (0);
+
+       return (error);
 }
 
 /*
- * MPSAFE
+ * MPALMOSTSAFE
  */
 int
 sys_linux_exit_group(struct linux_exit_group_args *args)
 {
-       struct exit_args newargs;
-       int error;
+       struct linux_emuldata *em, *e;
+       int rval;
 
-       newargs.sysmsg_iresult = 0;
-       newargs.rval = args->rval;
-       error = sys_exit(&newargs);
-       args->sysmsg_iresult = newargs.sysmsg_iresult;
-       return (error);
+       rval = args->rval;
+
+       get_mplock();
+
+       EMUL_LOCK();
+
+       em = emuldata_get(curproc);
+
+       if (em->s->refs == 1) {
+               exit1(W_EXITCODE(rval, 0));
+               /* notreached */
+
+               EMUL_UNLOCK();
+
+               rel_mplock();
+               return (0);
+       }
+       KKASSERT(em->proc == curproc);
+       em->flags |= EMUL_DIDKILL;
+       em->s->flags |= LINUX_LES_INEXITGROUP;
+       em->s->xstat = W_EXITCODE(rval, 0);
+
+       LIST_REMOVE(em, threads);
+       LIST_INSERT_HEAD(&em->s->threads, em, threads);
+       
+       while ((e = LIST_NEXT(em, threads)) != NULL) {
+               LIST_REMOVE(em, threads);
+               LIST_INSERT_AFTER(e, em, threads);
+               if ((e->flags & EMUL_DIDKILL) == 0) {
+                       e->flags |= EMUL_DIDKILL;
+                       KKASSERT(pfind(e->proc->p_pid) == e->proc);
+                       ksignal(e->proc, SIGKILL);
+               }
+       }
+
+
+       EMUL_UNLOCK();
+
+       exit1(W_EXITCODE(rval, 0));
+       rel_mplock();
+       /* notreached */
+
+       return (0);
 }
 
 /*
@@ -393,26 +448,26 @@ sys_linux_exit_group(struct linux_exit_group_args *args)
 int
 sys_linux_vfork(struct linux_vfork_args *args)
 {
+       struct lwp *lp = curthread->td_lwp;
+       struct proc *p2;
        int error;
 
-#ifdef DEBUG
-       if (ldebug(vfork))
-               kprintf(ARGS(vfork, ""));
-#endif
+       get_mplock();
+       error = fork1(lp, RFFDG | RFPROC | RFPPWAIT | RFMEM | RFPGLOCK, &p2);
+       if (error == 0) {
+               emuldata_init(curproc, p2, 0);
+
+               start_forked_proc(lp, p2);
+               args->sysmsg_fds[0] = p2->p_pid;
+               args->sysmsg_fds[1] = 0;
+       }
+       rel_mplock();
 
-       if ((error = sys_vfork((struct vfork_args *)args)) != 0)
-               return (error);
-       /* Are we the child? */
        if (args->sysmsg_iresult == 1)
                args->sysmsg_iresult = 0;
-       return (0);
-}
 
-#define CLONE_VM       0x100
-#define CLONE_FS       0x200
-#define CLONE_FILES    0x400
-#define CLONE_SIGHAND  0x800
-#define CLONE_PID      0x1000
+       return (error);
+}
 
 /*
  * MPALMOSTSAFE
@@ -420,66 +475,121 @@ sys_linux_vfork(struct linux_vfork_args *args)
 int
 sys_linux_clone(struct linux_clone_args *args)
 {
+       struct segment_descriptor *desc;
+       struct l_user_desc info;
+       int idx;
+       int a[2];
+
+       struct lwp *lp = curthread->td_lwp;
        int error, ff = RFPROC;
        struct proc *p2 = NULL;
        int exit_signal;
        vm_offset_t start;
-       struct rfork_args rf_args;
-
-#ifdef DEBUG
-       if (ldebug(clone)) {
-               kprintf(ARGS(clone, "flags %x, stack %x"), 
-                   (unsigned int)args->flags, (unsigned int)args->stack);
-               if (args->flags & CLONE_PID)
-                       kprintf(LMSG("CLONE_PID not yet supported"));
-       }
-#endif
-
-       if (!args->stack)
-               return (EINVAL);
 
        exit_signal = args->flags & 0x000000ff;
        if (exit_signal >= LINUX_NSIG)
                return (EINVAL);
-
        if (exit_signal <= LINUX_SIGTBLSZ)
                exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)];
 
-       /* RFTHREAD probably not necessary here, but it shouldn't hurt */
-       ff |= RFTHREAD;
-
-       if (args->flags & CLONE_VM)
+       if (args->flags & LINUX_CLONE_VM)
                ff |= RFMEM;
-       if (args->flags & CLONE_SIGHAND)
+       if (args->flags & LINUX_CLONE_SIGHAND)
                ff |= RFSIGSHARE;
-       if (!(args->flags & CLONE_FILES))
+       if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS)))
                ff |= RFFDG;
+       if ((args->flags & 0xffffff00) == LINUX_THREADING_FLAGS)
+               ff |= RFTHREAD;
+       if (args->flags & LINUX_CLONE_VFORK)
+               ff |= RFPPWAIT;
+       if (args->flags & LINUX_CLONE_PARENT_SETTID) {
+               if (args->parent_tidptr == NULL)
+                       return (EINVAL);
+       }
 
        error = 0;
        start = 0;
 
-       rf_args.flags = ff;
-       rf_args.sysmsg_iresult = 0;
        get_mplock();
-       if ((error = sys_rfork(&rf_args)) == 0) {
-               args->sysmsg_iresult = rf_args.sysmsg_iresult;
+       error = fork1(lp, ff | RFPGLOCK, &p2);
+       if (error) {
+               rel_mplock();
+               return error;
+       }
+
+       args->sysmsg_fds[0] = p2 ? p2->p_pid : 0;
+       args->sysmsg_fds[1] = 0;
+       
+       if (args->flags & (LINUX_CLONE_PARENT | LINUX_CLONE_THREAD))
+               proc_reparent(p2, curproc->p_pptr /* XXX */);
 
-               p2 = pfind(rf_args.sysmsg_iresult);
-               if (p2 == NULL)
-                       error = ESRCH;
+       emuldata_init(curproc, p2, args->flags);
+       linux_proc_fork(p2, curproc, args->child_tidptr);
+       /*
+        * XXX: this can't happen, p2 is never NULL, or else we'd have
+        *      other problems, too (see p2->p_sigparent == ...,
+        *      linux_proc_fork and emuldata_init.
+        */
+       if (p2 == NULL) {
+               error = ESRCH;
+       } else {
+               if (args->flags & LINUX_CLONE_PARENT_SETTID) {
+                       error = copyout(&p2->p_pid, args->parent_tidptr, sizeof(p2->p_pid));
+               }
        }
-       rel_mplock();
-       if (error == 0) {
-               p2->p_sigparent = exit_signal;
+
+       p2->p_sigparent = exit_signal;
+       if (args->stack) {
                ONLY_LWP_IN_PROC(p2)->lwp_md.md_regs->tf_esp =
-                                               (unsigned long)args->stack;
+                                       (unsigned long)args->stack;
+       }
 
-#ifdef DEBUG
-               if (ldebug(clone))
-                       kprintf(LMSG("clone: successful rfork to %ld"),
-                           (long)p2->p_pid);
+       if (args->flags & LINUX_CLONE_SETTLS) {
+               error = copyin((void *)curthread->td_lwp->lwp_md.md_regs->tf_esi, &info, sizeof(struct l_user_desc));
+               if (error) {
+                       kprintf("copyin of tf_esi to info failed\n");
+               } else {
+                       idx = info.entry_number;
+                       /*
+                        * We understand both our own entries such as the ones
+                        * we provide on linux_set_thread_area, as well as the
+                        * linux-type entries 6-8.
+                        */
+                       if ((idx < 6 || idx > 8) && (idx < GTLS_START)) {
+                               kprintf("LINUX_CLONE_SETTLS, invalid idx requested: %d\n", idx);
+                               goto out;
+                       }
+                       if (idx < GTLS_START) {
+                               idx -= 6;
+                       } else {
+#if 0 /* was SMP */
+                               idx -= (GTLS_START + mycpu->gd_cpuid * NGDT);
 #endif
+                               idx -= GTLS_START;
+                       }
+                       KKASSERT(idx >= 0);
+
+                       a[0] = LINUX_LDT_entry_a(&info);
+                       a[1] = LINUX_LDT_entry_b(&info);
+                       if (p2) {
+                               desc = &FIRST_LWP_IN_PROC(p2)->lwp_thread->td_tls.tls[idx];
+                               memcpy(desc, &a, sizeof(a));
+                       } else {
+                               kprintf("linux_clone... we don't have a p2\n");
+                       }
+               }
        }
+out:
+       if (p2)
+               start_forked_proc(lp, p2);
+
+       rel_mplock();
+#ifdef DEBUG
+       if (ldebug(clone))
+               kprintf(LMSG("clone: successful rfork to %ld"),
+                   (long)p2->p_pid);
+#endif
+
        return (error);
 }
 
@@ -588,7 +698,11 @@ linux_mmap_common(caddr_t linux_addr, size_t linux_len, int linux_prot,
                len = linux_len;
        }
 
-       prot = linux_prot | PROT_READ;
+       prot = linux_prot;
+
+       if (prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
+               prot |= PROT_READ | PROT_EXEC;
+
        if (linux_flags & LINUX_MAP_ANON) {
                fd = -1;
        } else {
@@ -753,6 +867,7 @@ sys_linux_modify_ldt(struct linux_modify_ldt_args *uap)
        struct i386_ldt_args *ldt;
        struct l_descriptor ld;
        union descriptor *desc;
+       int size, written;
 
        sg = stackgap_init();
 
@@ -772,6 +887,14 @@ sys_linux_modify_ldt(struct linux_modify_ldt_args *uap)
                uap->sysmsg_iresult = args.sysmsg_iresult *
                                      sizeof(union descriptor);
                break;
+       case 0x02: /* read_default_ldt = 0 */
+               size = 5*sizeof(struct l_desc_struct);
+               if (size > uap->bytecount)
+                       size = uap->bytecount;
+               for (written = error = 0; written < size && error == 0; written++)
+                       error = subyte((char *)uap->ptr + written, 0);
+               uap->sysmsg_iresult = written;
+               break;
        case 0x01: /* write_ldt */
        case 0x11: /* write_ldt */
                if (uap->bytecount != sizeof(ld))
@@ -820,7 +943,7 @@ sys_linux_sigaction(struct linux_sigaction_args *args)
        l_osigaction_t osa;
        l_sigaction_t linux_act, linux_oact;
        struct sigaction act, oact;
-       int error;
+       int error, sig;
 
 #ifdef DEBUG
        if (ldebug(sigaction))
@@ -840,8 +963,13 @@ sys_linux_sigaction(struct linux_sigaction_args *args)
                linux_to_bsd_sigaction(&linux_act, &act);
        }
 
+       if (args->sig <= LINUX_SIGTBLSZ)
+               sig = linux_to_bsd_signal[_SIG_IDX(args->sig)];
+       else
+               sig = args->sig;
+
        get_mplock();
-       error = kern_sigaction(args->sig, args->nsa ? &act : NULL,
+       error = kern_sigaction(sig, args->nsa ? &act : NULL,
                               args->osa ? &oact : NULL);
        rel_mplock();
 
@@ -982,3 +1110,150 @@ sys_linux_sigaltstack(struct linux_sigaltstack_args *uap)
 
        return (error);
 }
+
+int
+sys_linux_set_thread_area(struct linux_set_thread_area_args *args)
+{
+       struct segment_descriptor *desc;
+       struct l_user_desc info;
+       int error;
+       int idx;
+       int a[2];
+       int i;
+
+       error = copyin(args->desc, &info, sizeof(struct l_user_desc));
+       if (error)
+               return (EFAULT);
+
+#ifdef DEBUG
+       if (ldebug(set_thread_area))
+               kprintf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i\n"),
+                     info.entry_number,
+                     info.base_addr,
+                     info.limit,
+                     info.seg_32bit,
+                     info.contents,
+                     info.read_exec_only,
+                     info.limit_in_pages,
+                     info.seg_not_present,
+                     info.useable);
+#endif
+
+       idx = info.entry_number;
+       if (idx != -1 && (idx < 6 || idx > 8))
+               return (EINVAL);
+
+       if (idx == -1) {
+               /* -1 means finding the first free TLS entry */
+               for (i = 0; i < NGTLS; i++) {
+                       /*
+                        * try to determine if the TLS entry is empty by looking
+                        * at the lolimit entry.
+                        */
+                       if (curthread->td_tls.tls[idx].sd_lolimit == 0) {
+                               idx = i;
+                               break;
+                       }
+               }
+
+               if (idx == -1) {
+                       /*
+                        * By now we should have an index. If not, it means
+                        * that no entry is free, so return ESRCH.
+                        */
+                       return (ESRCH);
+               }
+       } else {
+               /* translate the index from Linux to ours */
+               idx -= 6;
+               KKASSERT(idx >= 0);
+       }
+
+       /* Tell the caller about the allocated entry number */
+#if 0 /* was SMP */
+       info.entry_number = GTLS_START + mycpu->gd_cpuid * NGDT + idx;
+#endif
+       info.entry_number = GTLS_START + idx;
+
+
+       error = copyout(&info, args->desc, sizeof(struct l_user_desc));
+       if (error)
+               return (error);
+
+       if (LINUX_LDT_empty(&info)) {
+               a[0] = 0;
+               a[1] = 0;
+       } else {
+               a[0] = LINUX_LDT_entry_a(&info);
+               a[1] = LINUX_LDT_entry_b(&info);
+       }
+
+       /*
+        * Update the TLS and the TLS entries in the GDT, but hold a critical
+        * section as required by set_user_TLS().
+        */
+       crit_enter();
+       desc = &curthread->td_tls.tls[idx];
+       memcpy(desc, &a, sizeof(a));
+       set_user_TLS();
+       crit_exit();
+
+       return (0);
+}
+
+int
+sys_linux_get_thread_area(struct linux_get_thread_area_args *args)
+{
+       struct segment_descriptor *sd;
+       struct l_desc_struct desc;
+       struct l_user_desc info;
+       int error;
+       int idx;
+
+#ifdef DEBUG
+       if (ldebug(get_thread_area))
+               kprintf(ARGS(get_thread_area, "%p"), args->desc);
+#endif
+
+       error = copyin(args->desc, &info, sizeof(struct l_user_desc));
+       if (error)
+               return (EFAULT);
+               
+       idx = info.entry_number;
+       if ((idx < 6 || idx > 8) && (idx < GTLS_START)) {
+               kprintf("sys_linux_get_thread_area, invalid idx requested: %d\n", idx);
+               return (EINVAL);
+       }
+
+       memset(&info, 0, sizeof(info));
+
+       /* translate the index from Linux to ours */
+       info.entry_number = idx;
+       if (idx < GTLS_START) {
+               idx -= 6;
+       } else {
+#if 0 /* was SMP */
+               idx -= (GTLS_START + mycpu->gd_cpuid * NGDT);
+#endif
+               idx -= GTLS_START;
+
+       }
+       KKASSERT(idx >= 0);
+
+       sd = &curthread->td_tls.tls[idx];
+       memcpy(&desc, sd, sizeof(desc));
+       info.base_addr = LINUX_GET_BASE(&desc);
+       info.limit = LINUX_GET_LIMIT(&desc);
+       info.seg_32bit = LINUX_GET_32BIT(&desc);
+       info.contents = LINUX_GET_CONTENTS(&desc);
+       info.read_exec_only = !LINUX_GET_WRITABLE(&desc);
+       info.limit_in_pages = LINUX_GET_LIMIT_PAGES(&desc);
+       info.seg_not_present = !LINUX_GET_PRESENT(&desc);
+       info.useable = LINUX_GET_USEABLE(&desc);
+
+       error = copyout(&info, args->desc, sizeof(struct l_user_desc));
+       if (error)
+               return (EFAULT);
+
+       return (0);
+}
index 6141090..8e246be 100644 (file)
@@ -323,6 +323,12 @@ struct     linux_ustat_args {
        l_dev_t dev;    char dev_[PAD_(l_dev_t)];
        struct l_ustat *        ubuf;   char ubuf_[PAD_(struct l_ustat *)];
 };
+struct linux_getppid_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       register_t dummy;
+};
 struct linux_sigaction_args {
 #ifdef _KERNEL
        struct sysmsg sysmsg;
@@ -604,6 +610,9 @@ struct      linux_clone_args {
 #endif
        l_int   flags;  char flags_[PAD_(l_int)];
        void *  stack;  char stack_[PAD_(void *)];
+       void *  parent_tidptr;  char parent_tidptr_[PAD_(void *)];
+       int     dummy;  char dummy_[PAD_(int)];
+       void *  child_tidptr;   char child_tidptr_[PAD_(void *)];
 };
 struct linux_newuname_args {
 #ifdef _KERNEL
@@ -1101,6 +1110,12 @@ struct   linux_fcntl64_args {
        l_uint  cmd;    char cmd_[PAD_(l_uint)];
        l_ulong arg;    char arg_[PAD_(l_ulong)];
 };
+struct linux_gettid_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       register_t dummy;
+};
 struct linux_setxattr_args {
 #ifdef _KERNEL
        struct sysmsg sysmsg;
@@ -1173,6 +1188,52 @@ struct   linux_fremovexattr_args {
 #endif
        register_t dummy;
 };
+struct linux_tkill_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       int     tid;    char tid_[PAD_(int)];
+       int     sig;    char sig_[PAD_(int)];
+};
+struct linux_sys_futex_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       void *  uaddr;  char uaddr_[PAD_(void *)];
+       int     op;     char op_[PAD_(int)];
+       int     val;    char val_[PAD_(int)];
+       struct l_timespec *     timeout;        char timeout_[PAD_(struct l_timespec *)];
+       void *  uaddr2; char uaddr2_[PAD_(void *)];
+       int     val3;   char val3_[PAD_(int)];
+};
+struct linux_sched_setaffinity_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_pid_t pid;    char pid_[PAD_(l_pid_t)];
+       l_uint  len;    char len_[PAD_(l_uint)];
+       l_ulong *       user_mask_ptr;  char user_mask_ptr_[PAD_(l_ulong *)];
+};
+struct linux_sched_getaffinity_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_pid_t pid;    char pid_[PAD_(l_pid_t)];
+       l_uint  len;    char len_[PAD_(l_uint)];
+       l_ulong *       user_mask_ptr;  char user_mask_ptr_[PAD_(l_ulong *)];
+};
+struct linux_set_thread_area_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       struct l_user_desc *    desc;   char desc_[PAD_(struct l_user_desc *)];
+};
+struct linux_get_thread_area_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       struct l_user_desc *    desc;   char desc_[PAD_(struct l_user_desc *)];
+};
 struct linux_fadvise64_args {
 #ifdef _KERNEL
        struct sysmsg sysmsg;
@@ -1185,6 +1246,249 @@ struct  linux_exit_group_args {
 #endif
        int     rval;   char rval_[PAD_(int)];
 };
+struct linux_epoll_create_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   size;   char size_[PAD_(l_int)];
+};
+struct linux_epoll_ctl_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   epfd;   char epfd_[PAD_(l_int)];
+       l_int   op;     char op_[PAD_(l_int)];
+       l_int   fd;     char fd_[PAD_(l_int)];
+       struct linux_epoll_event *      event;  char event_[PAD_(struct linux_epoll_event *)];
+};
+struct linux_epoll_wait_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   epfd;   char epfd_[PAD_(l_int)];
+       struct linux_epoll_event *      events; char events_[PAD_(struct linux_epoll_event *)];
+       l_int   maxevents;      char maxevents_[PAD_(l_int)];
+       l_int   timeout;        char timeout_[PAD_(l_int)];
+};
+struct linux_set_tid_address_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       int *   tidptr; char tidptr_[PAD_(int *)];
+};
+struct linux_clock_settime_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       clockid_t       which;  char which_[PAD_(clockid_t)];
+       struct l_timespec *     tp;     char tp_[PAD_(struct l_timespec *)];
+};
+struct linux_clock_gettime_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       clockid_t       which;  char which_[PAD_(clockid_t)];
+       struct l_timespec *     tp;     char tp_[PAD_(struct l_timespec *)];
+};
+struct linux_clock_getres_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       clockid_t       which;  char which_[PAD_(clockid_t)];
+       struct l_timespec *     tp;     char tp_[PAD_(struct l_timespec *)];
+};
+struct linux_clock_nanosleep_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       clockid_t       which;  char which_[PAD_(clockid_t)];
+       int     flags;  char flags_[PAD_(int)];
+       struct l_timespec *     rqtp;   char rqtp_[PAD_(struct l_timespec *)];
+       struct l_timespec *     rmtp;   char rmtp_[PAD_(struct l_timespec *)];
+};
+struct linux_statfs64_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       register_t dummy;
+};
+struct linux_tgkill_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       int     tgid;   char tgid_[PAD_(int)];
+       int     pid;    char pid_[PAD_(int)];
+       int     sig;    char sig_[PAD_(int)];
+};
+struct linux_utimes_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       char *  fname;  char fname_[PAD_(char *)];
+       struct l_timeval *      tptr;   char tptr_[PAD_(struct l_timeval *)];
+};
+struct linux_mq_open_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       const char *    name;   char name_[PAD_(const char *)];
+       int     oflag;  char oflag_[PAD_(int)];
+       mode_t  mode;   char mode_[PAD_(mode_t)];
+       struct mq_attr *        attr;   char attr_[PAD_(struct mq_attr *)];
+};
+struct linux_mq_getsetattr_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_mqd_t mqd;    char mqd_[PAD_(l_mqd_t)];
+       const struct mq_attr *  attr;   char attr_[PAD_(const struct mq_attr *)];
+       struct mq_attr *        oattr;  char oattr_[PAD_(struct mq_attr *)];
+};
+struct linux_openat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       l_int   flags;  char flags_[PAD_(l_int)];
+       l_int   mode;   char mode_[PAD_(l_int)];
+};
+struct linux_mkdirat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       l_int   mode;   char mode_[PAD_(l_int)];
+};
+struct linux_mknodat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       l_int   mode;   char mode_[PAD_(l_int)];
+       l_uint  dev;    char dev_[PAD_(l_uint)];
+};
+struct linux_fchownat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  filename;       char filename_[PAD_(char *)];
+       l_uid16_t       uid;    char uid_[PAD_(l_uid16_t)];
+       l_gid16_t       gid;    char gid_[PAD_(l_gid16_t)];
+       l_int   flag;   char flag_[PAD_(l_int)];
+};
+struct linux_futimesat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  fname;  char fname_[PAD_(char *)];
+       struct l_timeval *      tptr;   char tptr_[PAD_(struct l_timeval *)];
+};
+struct linux_fstatat64_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       struct l_stat64 *       statbuf;        char statbuf_[PAD_(struct l_stat64 *)];
+       l_int   flag;   char flag_[PAD_(l_int)];
+};
+struct linux_unlinkat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       l_int   flag;   char flag_[PAD_(l_int)];
+};
+struct linux_renameat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   olddfd; char olddfd_[PAD_(l_int)];
+       char *  from;   char from_[PAD_(char *)];
+       l_int   newdfd; char newdfd_[PAD_(l_int)];
+       char *  to;     char to_[PAD_(char *)];
+};
+struct linux_linkat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   olddfd; char olddfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       l_int   newdfd; char newdfd_[PAD_(l_int)];
+       char *  to;     char to_[PAD_(char *)];
+       l_int   flags;  char flags_[PAD_(l_int)];
+};
+struct linux_symlinkat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       char *  path;   char path_[PAD_(char *)];
+       l_int   newdfd; char newdfd_[PAD_(l_int)];
+       char *  to;     char to_[PAD_(char *)];
+};
+struct linux_readlinkat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  path;   char path_[PAD_(char *)];
+       char *  buf;    char buf_[PAD_(char *)];
+       l_int   count;  char count_[PAD_(l_int)];
+};
+struct linux_fchmodat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  filename;       char filename_[PAD_(char *)];
+       l_mode_t        mode;   char mode_[PAD_(l_mode_t)];
+};
+struct linux_faccessat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  filename;       char filename_[PAD_(char *)];
+       l_int   mode;   char mode_[PAD_(l_int)];
+};
+struct linux_set_robust_list_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       struct linux_robust_list_head * head;   char head_[PAD_(struct linux_robust_list_head *)];
+       l_size_t        len;    char len_[PAD_(l_size_t)];
+};
+struct linux_get_robust_list_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   pid;    char pid_[PAD_(l_int)];
+       struct linux_robust_list_head **        head;   char head_[PAD_(struct linux_robust_list_head **)];
+       l_size_t *      len;    char len_[PAD_(l_size_t *)];
+};
+struct linux_getcpu_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_uint *        pcpu;   char pcpu_[PAD_(l_uint *)];
+       l_uint *        pnode;  char pnode_[PAD_(l_uint *)];
+       void *  ptcache;        char ptcache_[PAD_(void *)];
+};
+struct linux_utimensat_args {
+#ifdef _KERNEL
+       struct sysmsg sysmsg;
+#endif
+       l_int   dfd;    char dfd_[PAD_(l_int)];
+       char *  fname;  char fname_[PAD_(char *)];
+       struct l_timespec *     tptr;   char tptr_[PAD_(struct l_timespec *)];
+       l_int   flag;   char flag_[PAD_(l_int)];
+};
 
 #ifdef COMPAT_43
 
@@ -1257,6 +1561,7 @@ int       sys_linux_ioctl (struct linux_ioctl_args *);
 int    sys_linux_fcntl (struct linux_fcntl_args *);
 int    sys_linux_olduname (struct linux_olduname_args *);
 int    sys_linux_ustat (struct linux_ustat_args *);
+int    sys_linux_getppid (struct linux_getppid_args *);
 int    sys_linux_sigaction (struct linux_sigaction_args *);
 int    sys_linux_sgetmask (struct linux_sgetmask_args *);
 int    sys_linux_ssetmask (struct linux_ssetmask_args *);
@@ -1367,6 +1672,7 @@ int       sys_linux_mincore (struct linux_mincore_args *);
 int    sys_linux_madvise (struct linux_madvise_args *);
 int    sys_linux_getdents64 (struct linux_getdents64_args *);
 int    sys_linux_fcntl64 (struct linux_fcntl64_args *);
+int    sys_linux_gettid (struct linux_gettid_args *);
 int    sys_linux_setxattr (struct linux_setxattr_args *);
 int    sys_linux_lsetxattr (struct linux_lsetxattr_args *);
 int    sys_linux_fsetxattr (struct linux_fsetxattr_args *);
@@ -1379,8 +1685,44 @@ int      sys_linux_flistxattr (struct linux_flistxattr_args *);
 int    sys_linux_removexattr (struct linux_removexattr_args *);
 int    sys_linux_lremovexattr (struct linux_lremovexattr_args *);
 int    sys_linux_fremovexattr (struct linux_fremovexattr_args *);
+int    sys_linux_tkill (struct linux_tkill_args *);
+int    sys_linux_sys_futex (struct linux_sys_futex_args *);
+int    sys_linux_sched_setaffinity (struct linux_sched_setaffinity_args *);
+int    sys_linux_sched_getaffinity (struct linux_sched_getaffinity_args *);
+int    sys_linux_set_thread_area (struct linux_set_thread_area_args *);
+int    sys_linux_get_thread_area (struct linux_get_thread_area_args *);
 int    sys_linux_fadvise64 (struct linux_fadvise64_args *);
 int    sys_linux_exit_group (struct linux_exit_group_args *);
+int    sys_linux_epoll_create (struct linux_epoll_create_args *);
+int    sys_linux_epoll_ctl (struct linux_epoll_ctl_args *);
+int    sys_linux_epoll_wait (struct linux_epoll_wait_args *);
+int    sys_linux_set_tid_address (struct linux_set_tid_address_args *);
+int    sys_linux_clock_settime (struct linux_clock_settime_args *);
+int    sys_linux_clock_gettime (struct linux_clock_gettime_args *);
+int    sys_linux_clock_getres (struct linux_clock_getres_args *);
+int    sys_linux_clock_nanosleep (struct linux_clock_nanosleep_args *);
+int    sys_linux_statfs64 (struct linux_statfs64_args *);
+int    sys_linux_tgkill (struct linux_tgkill_args *);
+int    sys_linux_utimes (struct linux_utimes_args *);
+int    sys_linux_mq_open (struct linux_mq_open_args *);
+int    sys_linux_mq_getsetattr (struct linux_mq_getsetattr_args *);
+int    sys_linux_openat (struct linux_openat_args *);
+int    sys_linux_mkdirat (struct linux_mkdirat_args *);
+int    sys_linux_mknodat (struct linux_mknodat_args *);
+int    sys_linux_fchownat (struct linux_fchownat_args *);
+int    sys_linux_futimesat (struct linux_futimesat_args *);
+int    sys_linux_fstatat64 (struct linux_fstatat64_args *);
+int    sys_linux_unlinkat (struct linux_unlinkat_args *);
+int    sys_linux_renameat (struct linux_renameat_args *);
+int    sys_linux_linkat (struct linux_linkat_args *);
+int    sys_linux_symlinkat (struct linux_symlinkat_args *);
+int    sys_linux_readlinkat (struct linux_readlinkat_args *);
+int    sys_linux_fchmodat (struct linux_fchmodat_args *);
+int    sys_linux_faccessat (struct linux_faccessat_args *);
+int    sys_linux_set_robust_list (struct linux_set_robust_list_args *);
+int    sys_linux_get_robust_list (struct linux_get_robust_list_args *);
+int    sys_linux_getcpu (struct linux_getcpu_args *);
+int    sys_linux_utimensat (struct linux_utimensat_args *);
 
 #endif /* !_LINUX_SYSPROTO_H_ */
 #undef PAD_
diff --git a/sys/emulation/linux/i386/linux_support.s b/sys/emulation/linux/i386/linux_support.s
new file mode 100644 (file)
index 0000000..2e4ad44
--- /dev/null
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2006,2007 Konstantin Belousov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "linux_assym.h"               /* system definitions */
+#include <machine/asmacros.h>          /* miscellaneous asm macros */
+#include <machine/cputypes.h>
+#include <machine/pmap.h>
+#include <machine/specialreg.h>
+
+#include "assym.s"
+
+/*
+ * A stack-based on-fault routine is used for more complex PCB_ONFAULT
+ * situations (such as memcpy/bcopy/bzero).  In this case the on-fault
+ * routine must be pushed on the stack.
+ */
+stack_onfault:
+       ret
+
+futex_fault_decx:
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx), %ecx
+futex_fault:
+       movl    $0,PCB_ONFAULT(%ecx)
+       movl    $EFAULT,%eax
+       ret
+
+futex_fault_pop:
+       addl    $4,%esp
+       movl    $0,PCB_ONFAULT(%ecx)
+       movl    $EFAULT,%eax
+       ret
+
+ENTRY(futex_xchgl)
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx),%ecx
+       pushl   $futex_fault
+       movl    $stack_onfault, PCB_ONFAULT(%ecx)
+       movl    8(%esp),%eax
+       movl    12(%esp),%edx
+       cmpl    $VM_MAX_USER_ADDRESS-4,%edx
+       ja      futex_fault_pop
+       xchgl   %eax,(%edx)
+       movl    16(%esp),%edx
+       movl    %eax,(%edx)
+       xorl    %eax,%eax
+       movl    %eax,PCB_ONFAULT(%ecx)
+       ret
+
+ENTRY(futex_addl)
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx),%ecx
+       pushl   $futex_fault
+       movl    $stack_onfault,PCB_ONFAULT(%ecx)
+       movl    8(%esp),%eax
+       movl    12(%esp),%edx
+       cmpl    $VM_MAX_USER_ADDRESS-4,%edx
+       ja      futex_fault_pop
+#ifdef SMP
+       lock
+#endif
+       xaddl   %eax,(%edx)
+       movl    16(%esp),%edx
+       movl    %eax,(%edx)
+       xorl    %eax,%eax
+       movl    %eax,PCB_ONFAULT(%ecx)
+       ret
+
+ENTRY(futex_orl)
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx),%ecx
+       pushl   $futex_fault_decx
+       movl    $stack_onfault,PCB_ONFAULT(%ecx)
+       movl    12(%esp),%edx
+       cmpl    $VM_MAX_USER_ADDRESS-4,%edx
+       ja      futex_fault_pop
+       movl    (%edx),%eax
+1:     movl    %eax,%ecx
+       orl     8(%esp),%ecx
+#ifdef SMP
+       lock
+#endif
+       cmpxchgl %ecx,(%edx)
+       jnz     1b
+futex_tail:
+       movl    16(%esp),%edx
+       movl    %eax,(%edx)
+       xorl    %eax,%eax
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx),%ecx
+       movl    %eax,PCB_ONFAULT(%ecx)
+       ret
+
+ENTRY(futex_andl)
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx),%ecx
+       pushl   $futex_fault_decx
+       movl    $stack_onfault,PCB_ONFAULT(%ecx)
+       movl    12(%esp),%edx
+       cmpl    $VM_MAX_USER_ADDRESS-4,%edx
+       ja      futex_fault_pop
+       movl    (%edx),%eax
+1:     movl    %eax,%ecx
+       andl    8(%esp),%ecx
+#ifdef SMP
+       lock
+#endif
+       cmpxchgl %ecx,(%edx)
+       jnz     1b
+       jmp     futex_tail
+
+ENTRY(futex_xorl)
+       movl    PCPU(curthread),%ecx
+       movl    TD_PCB(%ecx),%ecx
+       pushl   $futex_fault_decx
+       movl    $stack_onfault,PCB_ONFAULT(%ecx)
+       movl    12(%esp),%edx
+       cmpl    $VM_MAX_USER_ADDRESS-4,%edx
+       ja      futex_fault_pop
+       movl    (%edx),%eax
+1:     movl    %eax,%ecx
+       xorl    8(%esp),%ecx
+#ifdef SMP
+       lock
+#endif
+       cmpxchgl %ecx,(%edx)
+       jnz     1b
+       jmp     futex_tail
index 157ed34..85cf4ed 100644 (file)
@@ -59,7 +59,7 @@
 #define        LINUX_SYS_chroot        61
 #define        LINUX_SYS_linux_ustat   62
 #define        LINUX_SYS_dup2  63
-#define        LINUX_SYS_getppid       64
+#define        LINUX_SYS_linux_getppid 64
 #define        LINUX_SYS_getpgrp       65
 #define        LINUX_SYS_setsid        66
 #define        LINUX_SYS_linux_sigaction       67
 #define        LINUX_SYS_linux_madvise 219
 #define        LINUX_SYS_linux_getdents64      220
 #define        LINUX_SYS_linux_fcntl64 221
+#define        LINUX_SYS_linux_gettid  224
 #define        LINUX_SYS_linux_setxattr        226
 #define        LINUX_SYS_linux_lsetxattr       227
 #define        LINUX_SYS_linux_fsetxattr       228
 #define        LINUX_SYS_linux_removexattr     235
 #define        LINUX_SYS_linux_lremovexattr    236
 #define        LINUX_SYS_linux_fremovexattr    237
+#define        LINUX_SYS_linux_tkill   238
+#define        LINUX_SYS_linux_sys_futex       240
+#define        LINUX_SYS_linux_sched_setaffinity       241
+#define        LINUX_SYS_linux_sched_getaffinity       242
+#define        LINUX_SYS_linux_set_thread_area 243
+#define        LINUX_SYS_linux_get_thread_area 244
 #define        LINUX_SYS_linux_fadvise64       250
 #define        LINUX_SYS_linux_exit_group      252
-#define        LINUX_SYS_MAXSYSCALL    268
+#define        LINUX_SYS_linux_epoll_create    254
+#define        LINUX_SYS_linux_epoll_ctl       255
+#define        LINUX_SYS_linux_epoll_wait      256
+#define        LINUX_SYS_linux_set_tid_address 258
+#define        LINUX_SYS_linux_clock_settime   264
+#define        LINUX_SYS_linux_clock_gettime   265
+#define        LINUX_SYS_linux_clock_getres    266
+#define        LINUX_SYS_linux_clock_nanosleep 267
+#define        LINUX_SYS_linux_statfs64        268
+#define        LINUX_SYS_linux_tgkill  270
+#define        LINUX_SYS_linux_utimes  271
+#define        LINUX_SYS_linux_mq_open 277
+#define        LINUX_SYS_mq_unlink     278
+#define        LINUX_SYS_mq_timedsend  279
+#define        LINUX_SYS_mq_timedreceive       280
+#define        LINUX_SYS_mq_notify     281
+#define        LINUX_SYS_linux_mq_getsetattr   282
+#define        LINUX_SYS_linux_openat  295
+#define        LINUX_SYS_linux_mkdirat 296
+#define        LINUX_SYS_linux_mknodat 297
+#define        LINUX_SYS_linux_fchownat        298
+#define        LINUX_SYS_linux_futimesat       299
+#define        LINUX_SYS_linux_fstatat64       300
+#define        LINUX_SYS_linux_unlinkat        301
+#define        LINUX_SYS_linux_renameat        302
+#define        LINUX_SYS_linux_linkat  303
+#define        LINUX_SYS_linux_symlinkat       304
+#define        LINUX_SYS_linux_readlinkat      305
+#define        LINUX_SYS_linux_fchmodat        306
+#define        LINUX_SYS_linux_faccessat       307
+#define        LINUX_SYS_linux_set_robust_list 311
+#define        LINUX_SYS_linux_get_robust_list 312
+#define        LINUX_SYS_linux_getcpu  318
+#define        LINUX_SYS_linux_utimensat       320
+#define        LINUX_SYS_MAXSYSCALL    338
index 5e81128..c6948bb 100644 (file)
@@ -82,7 +82,7 @@ struct sysent linux_sysent[] = {
        { AS(chroot_args), (sy_call_t *)sys_chroot },   /* 61 = chroot */
        { AS(linux_ustat_args), (sy_call_t *)sys_linux_ustat }, /* 62 = linux_ustat */
        { AS(dup2_args), (sy_call_t *)sys_dup2 },       /* 63 = dup2 */
-       { 0, (sy_call_t *)sys_getppid },                /* 64 = getppid */
+       { 0, (sy_call_t *)sys_linux_getppid },          /* 64 = linux_getppid */
        { 0, (sy_call_t *)sys_getpgrp },                /* 65 = getpgrp */
        { 0, (sy_call_t *)sys_setsid },                 /* 66 = setsid */
        { AS(linux_sigaction_args), (sy_call_t *)sys_linux_sigaction }, /* 67 = linux_sigaction */
@@ -242,7 +242,7 @@ struct sysent linux_sysent[] = {
        { AS(linux_fcntl64_args), (sy_call_t *)sys_linux_fcntl64 },     /* 221 = linux_fcntl64 */
        { 0, (sy_call_t *)sys_nosys },                  /* 222 = none */
        { 0, (sy_call_t *)sys_nosys },                  /* 223 = none */
-       { 0, (sy_call_t *)sys_nosys },                  /* 224 = linux_gettid */
+       { 0, (sy_call_t *)sys_linux_gettid },           /* 224 = linux_gettid */
        { 0, (sy_call_t *)sys_nosys },                  /* 225 = linux_readahead */
        { 0, (sy_call_t *)sys_linux_setxattr },         /* 226 = linux_setxattr */
        { 0, (sy_call_t *)sys_linux_lsetxattr },        /* 227 = linux_lsetxattr */
@@ -256,13 +256,13 @@ struct sysent linux_sysent[] = {
        { 0, (sy_call_t *)sys_linux_removexattr },      /* 235 = linux_removexattr */
        { 0, (sy_call_t *)sys_linux_lremovexattr },     /* 236 = linux_lremovexattr */
        { 0, (sy_call_t *)sys_linux_fremovexattr },     /* 237 = linux_fremovexattr */
-       { 0, (sy_call_t *)sys_nosys },                  /* 238 = linux_tkill */
+       { AS(linux_tkill_args), (sy_call_t *)sys_linux_tkill }, /* 238 = linux_tkill */
        { 0, (sy_call_t *)sys_nosys },                  /* 239 = linux_sendfile64 */
-       { 0, (sy_call_t *)sys_nosys },                  /* 240 = linux_futex */
-       { 0, (sy_call_t *)sys_nosys },                  /* 241 = linux_sched_setaffinity */
-       { 0, (sy_call_t *)sys_nosys },                  /* 242 = linux_sched_getaffinity */
-       { 0, (sy_call_t *)sys_nosys },                  /* 243 = linux_set_thread_area */
-       { 0, (sy_call_t *)sys_nosys },                  /* 244 = linux_get_thread_area */
+       { AS(linux_sys_futex_args), (sy_call_t *)sys_linux_sys_futex }, /* 240 = linux_sys_futex */
+       { AS(linux_sched_setaffinity_args), (sy_call_t *)sys_linux_sched_setaffinity }, /* 241 = linux_sched_setaffinity */
+       { AS(linux_sched_getaffinity_args), (sy_call_t *)sys_linux_sched_getaffinity }, /* 242 = linux_sched_getaffinity */
+       { AS(linux_set_thread_area_args), (sy_call_t *)sys_linux_set_thread_area },     /* 243 = linux_set_thread_area */
+       { AS(linux_get_thread_area_args), (sy_call_t *)sys_linux_get_thread_area },     /* 244 = linux_get_thread_area */
        { 0, (sy_call_t *)sys_nosys },                  /* 245 = linux_io_setup */
        { 0, (sy_call_t *)sys_nosys },                  /* 246 = linux_io_destroy */
        { 0, (sy_call_t *)sys_nosys },                  /* 247 = linux_io_getevents */
@@ -272,18 +272,88 @@ struct sysent linux_sysent[] = {
        { 0, (sy_call_t *)sys_nosys },                  /* 251 =  */
        { AS(linux_exit_group_args), (sy_call_t *)sys_linux_exit_group },       /* 252 = linux_exit_group */
        { 0, (sy_call_t *)sys_nosys },                  /* 253 = linux_lookup_dcookie */
-       { 0, (sy_call_t *)sys_nosys },                  /* 254 = linux_epoll_create */
-       { 0, (sy_call_t *)sys_nosys },                  /* 255 = linux_epoll_ctl */
-       { 0, (sy_call_t *)sys_nosys },                  /* 256 = linux_epoll_wait */
+       { AS(linux_epoll_create_args), (sy_call_t *)sys_linux_epoll_create },   /* 254 = linux_epoll_create */
+       { AS(linux_epoll_ctl_args), (sy_call_t *)sys_linux_epoll_ctl }, /* 255 = linux_epoll_ctl */
+       { AS(linux_epoll_wait_args), (sy_call_t *)sys_linux_epoll_wait },       /* 256 = linux_epoll_wait */
        { 0, (sy_call_t *)sys_nosys },                  /* 257 = linux_remap_file_pages */
-       { 0, (sy_call_t *)sys_nosys },                  /* 258 = linux_set_tid_address */
+       { AS(linux_set_tid_address_args), (sy_call_t *)sys_linux_set_tid_address },     /* 258 = linux_set_tid_address */
        { 0, (sy_call_t *)sys_nosys },                  /* 259 = linux_timer_create */
        { 0, (sy_call_t *)sys_nosys },                  /* 260 = linux_timer_settime */
        { 0, (sy_call_t *)sys_nosys },                  /* 261 = linux_timer_gettime */
        { 0, (sy_call_t *)sys_nosys },                  /* 262 = linux_timer_getoverrun */
        { 0, (sy_call_t *)sys_nosys },                  /* 263 = linux_timer_delete */
-       { 0, (sy_call_t *)sys_nosys },                  /* 264 = linux_clock_settime */
-       { 0, (sy_call_t *)sys_nosys },                  /* 265 = linux_clock_gettime */
-       { 0, (sy_call_t *)sys_nosys },                  /* 266 = linux_clock_getres */
-       { 0, (sy_call_t *)sys_nosys },                  /* 267 = linux_clock_nanosleep */
+       { AS(linux_clock_settime_args), (sy_call_t *)sys_linux_clock_settime }, /* 264 = linux_clock_settime */
+       { AS(linux_clock_gettime_args), (sy_call_t *)sys_linux_clock_gettime }, /* 265 = linux_clock_gettime */
+       { AS(linux_clock_getres_args), (sy_call_t *)sys_linux_clock_getres },   /* 266 = linux_clock_getres */
+       { AS(linux_clock_nanosleep_args), (sy_call_t *)sys_linux_clock_nanosleep },     /* 267 = linux_clock_nanosleep */
+       { 0, (sy_call_t *)sys_linux_statfs64 },         /* 268 = linux_statfs64 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 269 = linux_fstatfs64 */
+       { AS(linux_tgkill_args), (sy_call_t *)sys_linux_tgkill },       /* 270 = linux_tgkill */
+       { AS(linux_utimes_args), (sy_call_t *)sys_linux_utimes },       /* 271 = linux_utimes */
+       { 0, (sy_call_t *)sys_nosys },                  /* 272 = linux_fadvise64_64 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 273 = linux_nonexistant */
+       { 0, (sy_call_t *)sys_nosys },                  /* 274 = linux_mbind */
+       { 0, (sy_call_t *)sys_nosys },                  /* 275 = linux_get_mempolicy */
+       { 0, (sy_call_t *)sys_nosys },                  /* 276 = linux_set_mempolicy */
+       { AS(linux_mq_open_args), (sy_call_t *)sys_linux_mq_open },     /* 277 = linux_mq_open */
+       { AS(mq_unlink_args), (sy_call_t *)sys_mq_unlink },     /* 278 = mq_unlink */
+       { AS(mq_timedsend_args), (sy_call_t *)sys_mq_timedsend },       /* 279 = mq_timedsend */
+       { AS(mq_timedreceive_args), (sy_call_t *)sys_mq_timedreceive }, /* 280 = mq_timedreceive */
+       { AS(mq_notify_args), (sy_call_t *)sys_mq_notify },     /* 281 = mq_notify */
+       { AS(linux_mq_getsetattr_args), (sy_call_t *)sys_linux_mq_getsetattr }, /* 282 = linux_mq_getsetattr */
+       { 0, (sy_call_t *)sys_nosys },                  /* 283 = linux_kexec_load */
+       { 0, (sy_call_t *)sys_nosys },                  /* 284 = linux_waitid */
+       { 0, (sy_call_t *)sys_nosys },                  /* 285 = linux_nonexistant2 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 286 = linux_add_key */
+       { 0, (sy_call_t *)sys_nosys },                  /* 287 = linux_request_key */
+       { 0, (sy_call_t *)sys_nosys },                  /* 288 = linux_keyctl */
+       { 0, (sy_call_t *)sys_nosys },                  /* 289 = linux_ioprio_set */
+       { 0, (sy_call_t *)sys_nosys },                  /* 290 = linux_ioprio_get */
+       { 0, (sy_call_t *)sys_nosys },                  /* 291 = linux_inotify_init */
+       { 0, (sy_call_t *)sys_nosys },                  /* 292 = linux_inotify_add_watch */
+       { 0, (sy_call_t *)sys_nosys },                  /* 293 = linux_inotify_rm_watch */
+       { 0, (sy_call_t *)sys_nosys },                  /* 294 = linux_migrate_pages */
+       { AS(linux_openat_args), (sy_call_t *)sys_linux_openat },       /* 295 = linux_openat */
+       { AS(linux_mkdirat_args), (sy_call_t *)sys_linux_mkdirat },     /* 296 = linux_mkdirat */
+       { AS(linux_mknodat_args), (sy_call_t *)sys_linux_mknodat },     /* 297 = linux_mknodat */
+       { AS(linux_fchownat_args), (sy_call_t *)sys_linux_fchownat },   /* 298 = linux_fchownat */
+       { AS(linux_futimesat_args), (sy_call_t *)sys_linux_futimesat }, /* 299 = linux_futimesat */
+       { AS(linux_fstatat64_args), (sy_call_t *)sys_linux_fstatat64 }, /* 300 = linux_fstatat64 */
+       { AS(linux_unlinkat_args), (sy_call_t *)sys_linux_unlinkat },   /* 301 = linux_unlinkat */
+       { AS(linux_renameat_args), (sy_call_t *)sys_linux_renameat },   /* 302 = linux_renameat */
+       { AS(linux_linkat_args), (sy_call_t *)sys_linux_linkat },       /* 303 = linux_linkat */
+       { AS(linux_symlinkat_args), (sy_call_t *)sys_linux_symlinkat }, /* 304 = linux_symlinkat */
+       { AS(linux_readlinkat_args), (sy_call_t *)sys_linux_readlinkat },       /* 305 = linux_readlinkat */
+       { AS(linux_fchmodat_args), (sy_call_t *)sys_linux_fchmodat },   /* 306 = linux_fchmodat */
+       { AS(linux_faccessat_args), (sy_call_t *)sys_linux_faccessat }, /* 307 = linux_faccessat */
+       { 0, (sy_call_t *)sys_nosys },                  /* 308 = linux_pselect6 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 309 = linux_ppoll */
+       { 0, (sy_call_t *)sys_nosys },                  /* 310 = linux_unshare */
+       { AS(linux_set_robust_list_args), (sy_call_t *)sys_linux_set_robust_list },     /* 311 = linux_set_robust_list */
+       { AS(linux_get_robust_list_args), (sy_call_t *)sys_linux_get_robust_list },     /* 312 = linux_get_robust_list */
+       { 0, (sy_call_t *)sys_nosys },                  /* 313 = linux_splice */
+       { 0, (sy_call_t *)sys_nosys },                  /* 314 = linux_sync_file_range */
+       { 0, (sy_call_t *)sys_nosys },                  /* 315 = linux_tee */
+       { 0, (sy_call_t *)sys_nosys },                  /* 316 = linux_vmsplice */
+       { 0, (sy_call_t *)sys_nosys },                  /* 317 = linux_move_pages */
+       { AS(linux_getcpu_args), (sy_call_t *)sys_linux_getcpu },       /* 318 = linux_getcpu */
+       { 0, (sy_call_t *)sys_nosys },                  /* 319 = linux_epoll_pwait */
+       { AS(linux_utimensat_args), (sy_call_t *)sys_linux_utimensat }, /* 320 = linux_utimensat */
+       { 0, (sy_call_t *)sys_nosys },                  /* 321 = linux_signalfd */
+       { 0, (sy_call_t *)sys_nosys },                  /* 322 = linux_timerfd_create */
+       { 0, (sy_call_t *)sys_nosys },                  /* 323 = linux_eventfd */
+       { 0, (sy_call_t *)sys_nosys },                  /* 324 = linux_fallocate */
+       { 0, (sy_call_t *)sys_nosys },                  /* 325 = linux_timerfd_settime */
+       { 0, (sy_call_t *)sys_nosys },                  /* 326 = linux_timerfd_gettime */
+       { 0, (sy_call_t *)sys_nosys },                  /* 327 = linux_signalfd4 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 328 = linux_eventfd2 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 329 = linux_epoll_create1 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 330 = linux_dup3 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 331 = linux_pipe2 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 332 = linux_inotify_init1 */
+       { 0, (sy_call_t *)sys_nosys },                  /* 333 = linux_preadv */
+       { 0, (sy_call_t *)sys_nosys },                  /* 334 = linux_pwritev */
+       { 0, (sy_call_t *)sys_nosys },                  /* 335 = linux_rt_tgsigqueueinfo */
+       { 0, (sy_call_t *)sys_nosys },                  /* 336 = linux_perf_event_open */
+       { 0, (sy_call_t *)sys_nosys },                  /* 337 = linux_recvmmsg */
 };
index 41a5a1a..abe895b 100644 (file)
@@ -48,6 +48,7 @@
 #include <sys/signalvar.h>
 #include <sys/sysent.h>
 #include <sys/sysproto.h>
+#include <sys/eventhandler.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -62,6 +63,8 @@
 #include "linux_proto.h"
 #include "../linux_signal.h"
 #include "../linux_util.h"
+#include "../linux_futex.h"
+#include "../linux_emuldata.h"
 
 MODULE_VERSION(linux, 1);
 
@@ -96,6 +99,9 @@ static void   linux_prepsyscall (struct trapframe *tf, int *args,
 static void     linux_sendsig (sig_t catcher, int sig, sigset_t *mask,
                                   u_long code);
 
+static eventhandler_tag linux_exec_tag;
+static eventhandler_tag linux_exit_tag;
+
 /*
  * Linux syscalls return negative errno's, we do positive and map them
  */
@@ -114,7 +120,7 @@ static int bsd_to_linux_errno[ELAST + 1] = {
 int bsd_to_linux_signal[LINUX_SIGTBLSZ] = {
        LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL,
        LINUX_SIGTRAP, LINUX_SIGABRT, 0, LINUX_SIGFPE,
-       LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, 0,
+       LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, LINUX_SIGSYS,
        LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, LINUX_SIGURG,
        LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, LINUX_SIGCHLD,
        LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, LINUX_SIGXCPU,
@@ -130,7 +136,7 @@ int linux_to_bsd_signal[LINUX_SIGTBLSZ] = {
        SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP,
        SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,
        SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
-       SIGIO, SIGURG, 0
+       SIGIO, SIGURG, SIGSYS
 };
 
 #define LINUX_T_UNKNOWN  255
@@ -788,7 +794,7 @@ exec_linux_imgact_try(struct image_params *imgp)
 struct sysentvec linux_sysvec = {
        LINUX_SYS_MAXSYSCALL,
        linux_sysent,
-       0xff,
+       0xffffffff,
        LINUX_SIGTBLSZ,
        bsd_to_linux_signal,
        ELAST + 1, 
@@ -808,7 +814,7 @@ struct sysentvec linux_sysvec = {
 struct sysentvec elf_linux_sysvec = {
        LINUX_SYS_MAXSYSCALL,
        linux_sysent,
-       0xff,
+       0xffffffff,
        LINUX_SIGTBLSZ,
        bsd_to_linux_signal,
        ELAST + 1,
@@ -913,8 +919,15 @@ linux_elf_modevent(module_t mod, int type, void *data)
                if (error == 0) {
                        if (bootverbose)
                                kprintf("Linux ELF exec handler installed\n");
-               } else
+               } else {
                        kprintf("cannot insert Linux ELF brand handler\n");
+               }
+               EMUL_LOCKINIT();
+               lockinit(&futex_mtx, "linftxs", 0, LK_CANRECURSE);
+               linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_transition,
+                   NULL, 1000);
+               linux_exit_tag = EVENTHANDLER_REGISTER(process_exit, emuldata_exit,
+                   NULL, 1000);
                break;
        case MOD_UNLOAD:
                for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL;
@@ -930,8 +943,13 @@ linux_elf_modevent(module_t mod, int type, void *data)
                if (error == 0) {
                        if (bootverbose)
                                kprintf("Linux ELF exec handler removed\n");
-               } else
+               } else {
                        kprintf("Could not deinstall ELF interpreter entry\n");
+               }
+               EVENTHANDLER_DEREGISTER(process_exec, linux_exec_tag);
+               EVENTHANDLER_DEREGISTER(process_exit, linux_exit_tag);
+               lockuninit(&futex_mtx);
+               EMUL_LOCKUNINIT();
                break;
        default:
                break;
index 98bebea..0351fee 100644 (file)
@@ -54,6 +54,7 @@ union sysunion {
        struct  linux_fcntl_args linux_fcntl;
        struct  linux_olduname_args linux_olduname;
        struct  linux_ustat_args linux_ustat;
+       struct  linux_getppid_args linux_getppid;
        struct  linux_sigaction_args linux_sigaction;
        struct  linux_sgetmask_args linux_sgetmask;
        struct  linux_ssetmask_args linux_ssetmask;
@@ -164,6 +165,7 @@ union sysunion {
        struct  linux_madvise_args linux_madvise;
        struct  linux_getdents64_args linux_getdents64;
        struct  linux_fcntl64_args linux_fcntl64;
+       struct  linux_gettid_args linux_gettid;
        struct  linux_setxattr_args linux_setxattr;
        struct  linux_lsetxattr_args linux_lsetxattr;
        struct  linux_fsetxattr_args linux_fsetxattr;
@@ -176,6 +178,42 @@ union sysunion {
        struct  linux_removexattr_args linux_removexattr;
        struct  linux_lremovexattr_args linux_lremovexattr;
        struct  linux_fremovexattr_args linux_fremovexattr;
+       struct  linux_tkill_args linux_tkill;
+       struct  linux_sys_futex_args linux_sys_futex;
+       struct  linux_sched_setaffinity_args linux_sched_setaffinity;
+       struct  linux_sched_getaffinity_args linux_sched_getaffinity;
+       struct  linux_set_thread_area_args linux_set_thread_area;
+       struct  linux_get_thread_area_args linux_get_thread_area;
        struct  linux_fadvise64_args linux_fadvise64;
        struct  linux_exit_group_args linux_exit_group;
+       struct  linux_epoll_create_args linux_epoll_create;
+       struct  linux_epoll_ctl_args linux_epoll_ctl;
+       struct  linux_epoll_wait_args linux_epoll_wait;
+       struct  linux_set_tid_address_args linux_set_tid_address;
+       struct  linux_clock_settime_args linux_clock_settime;
+       struct  linux_clock_gettime_args linux_clock_gettime;
+       struct  linux_clock_getres_args linux_clock_getres;
+       struct  linux_clock_nanosleep_args linux_clock_nanosleep;
+       struct  linux_statfs64_args linux_statfs64;
+       struct  linux_tgkill_args linux_tgkill;
+       struct  linux_utimes_args linux_utimes;
+       struct  linux_mq_open_args linux_mq_open;
+       struct  linux_mq_getsetattr_args linux_mq_getsetattr;
+       struct  linux_openat_args linux_openat;
+       struct  linux_mkdirat_args linux_mkdirat;
+       struct  linux_mknodat_args linux_mknodat;
+       struct  linux_fchownat_args linux_fchownat;
+       struct  linux_futimesat_args linux_futimesat;
+       struct  linux_fstatat64_args linux_fstatat64;
+       struct  linux_unlinkat_args linux_unlinkat;
+       struct  linux_renameat_args linux_renameat;
+       struct  linux_linkat_args linux_linkat;
+       struct  linux_symlinkat_args linux_symlinkat;
+       struct  linux_readlinkat_args linux_readlinkat;
+       struct  linux_fchmodat_args linux_fchmodat;
+       struct  linux_faccessat_args linux_faccessat;
+       struct  linux_set_robust_list_args linux_set_robust_list;
+       struct  linux_get_robust_list_args linux_get_robust_list;
+       struct  linux_getcpu_args linux_getcpu;
+       struct  linux_utimensat_args linux_utimensat;
 };
index 8d50ae9..38716d4 100644 (file)
 61     NOPROTO LINUX   { int chroot(char *path); }
 62     STD     LINUX   { int linux_ustat(l_dev_t dev, struct l_ustat *ubuf); }
 63     NOPROTO LINUX   { int dup2(u_int from, u_int to); }
-64     NOPROTO LINUX   { int getppid(void); }
+64     STD     LINUX   { int linux_getppid(void); }
 65     NOPROTO LINUX   { int getpgrp(void); }
 66     NOPROTO LINUX   { int setsid(void); }
 67     STD     LINUX   { int linux_sigaction(l_int sig, l_osigaction_t *nsa, \
                                l_int arg3, void *ptr, l_long arg5); }
 118    NOPROTO LINUX   { int fsync(int fd); }
 119    STD     LINUX   { int linux_sigreturn(struct l_sigframe *sfp); }
-120    STD     LINUX   { int linux_clone(l_int flags, void *stack); }
+120    STD     LINUX   { int linux_clone(l_int flags, void *stack, \
+                               void *parent_tidptr, int dummy, void *child_tidptr); }
 121    NOPROTO LINUX   { int setdomainname(char *name, int len); }
 122    STD     LINUX   { int linux_newuname(struct l_new_utsname *buf); }
 123    STD     LINUX   { int linux_modify_ldt(l_int func, void *ptr, \
                                l_ulong arg); }
 222    UNIMPL  LINUX   none
 223    UNIMPL  LINUX   none
-224    UNIMPL  LINUX   linux_gettid
+224    STD     LINUX    { int linux_gettid(void); }
 225    UNIMPL  LINUX   linux_readahead
 226    STD     LINUX   { int linux_setxattr(void); }
 227    STD     LINUX   { int linux_lsetxattr(void); }
 235    STD     LINUX   { int linux_removexattr(void); }
 236    STD     LINUX   { int linux_lremovexattr(void); }
 237    STD     LINUX   { int linux_fremovexattr(void); }
-238    UNIMPL  LINUX   linux_tkill
+238    STD     LINUX   { int linux_tkill(int tid, int sig); }
 239    UNIMPL  LINUX   linux_sendfile64
-240    UNIMPL  LINUX   linux_futex
-241    UNIMPL  LINUX   linux_sched_setaffinity
-242    UNIMPL  LINUX   linux_sched_getaffinity
-243    UNIMPL  LINUX   linux_set_thread_area
-244    UNIMPL  LINUX   linux_get_thread_area
+240    STD     LINUX   { int linux_sys_futex(void *uaddr, int op, int val, \
+                                       struct l_timespec *timeout, void *uaddr2, int val3); }
+241    STD     LINUX   { int linux_sched_setaffinity(l_pid_t pid, l_uint len, \
+                                               l_ulong *user_mask_ptr); }
+242    STD     LINUX   { int linux_sched_getaffinity(l_pid_t pid, l_uint len, \
+                                               l_ulong *user_mask_ptr); }
+243    STD     LINUX   { int linux_set_thread_area(struct l_user_desc *desc); }
+244    STD     LINUX   { int linux_get_thread_area(struct l_user_desc *desc); }
 245    UNIMPL  LINUX   linux_io_setup
 246    UNIMPL  LINUX   linux_io_destroy
 247    UNIMPL  LINUX   linux_io_getevents
 251    UNIMPL  LINUX   
 252    STD     LINUX   { void linux_exit_group(int rval); }
 253    UNIMPL  LINUX   linux_lookup_dcookie
-254    UNIMPL  LINUX   linux_epoll_create
-255    UNIMPL  LINUX   linux_epoll_ctl
-256    UNIMPL  LINUX   linux_epoll_wait
+254    STD     LINUX   { int linux_epoll_create(l_int size); }
+255    STD     LINUX   { int linux_epoll_ctl(l_int epfd, l_int op, l_int fd, \
+                                       struct linux_epoll_event *event); }
+256    STD     LINUX   { int linux_epoll_wait(l_int epfd, struct linux_epoll_event *events, \
+                                       l_int maxevents, l_int timeout); }
 257    UNIMPL  LINUX   linux_remap_file_pages
-258    UNIMPL  LINUX   linux_set_tid_address
+258    STD     LINUX   { int linux_set_tid_address(int *tidptr); }
 259    UNIMPL  LINUX   linux_timer_create
 260    UNIMPL  LINUX   linux_timer_settime
 261    UNIMPL  LINUX   linux_timer_gettime
 262    UNIMPL  LINUX   linux_timer_getoverrun
 263    UNIMPL  LINUX   linux_timer_delete
-264    UNIMPL  LINUX   linux_clock_settime
-265    UNIMPL  LINUX   linux_clock_gettime
-266    UNIMPL  LINUX   linux_clock_getres
-267    UNIMPL  LINUX   linux_clock_nanosleep
-
+264    STD     LINUX   { int linux_clock_settime(clockid_t which, struct l_timespec *tp); }
+265    STD     LINUX   { int linux_clock_gettime(clockid_t which, struct l_timespec *tp); }
+266    STD     LINUX   { int linux_clock_getres(clockid_t which, struct l_timespec *tp); }
+267    STD     LINUX   { int linux_clock_nanosleep(clockid_t which, int flags, \
+                                               struct l_timespec *rqtp, struct l_timespec *rmtp); }
+268    STD     LINUX   { int linux_statfs64(void); }
+269    UNIMPL  LINUX   linux_fstatfs64
+270    STD     LINUX   { int linux_tgkill(int tgid, int pid, int sig); }
+271    STD     LINUX   { int linux_utimes(char *fname, \
+                                       struct l_timeval *tptr); }
+272    UNIMPL  LINUX   linux_fadvise64_64
+273    UNIMPL  LINUX   linux_nonexistant
+274    UNIMPL  LINUX   linux_mbind
+275    UNIMPL  LINUX   linux_get_mempolicy
+276    UNIMPL  LINUX   linux_set_mempolicy
+277    STD     LINUX   { int linux_mq_open(const char *name, int oflag, mode_t mode, \
+                       struct mq_attr *attr); }
+278    NOPROTO LINUX   { int mq_unlink(const char *name); }
+279    NOPROTO LINUX   { int mq_timedsend(l_mqd_t mqd, const char *msg_ptr, \
+                       size_t msg_len, unsigned int msg_prio, const struct \
+                       l_timespec *abs_timeout); }
+280    NOPROTO LINUX   { int mq_timedreceive(l_mqd_t mqd, char *msg_ptr, \
+                       size_t msg_len, unsigned int msg_prio, const struct \
+                       l_timespec *abs_timeout); }
+281    NOPROTO LINUX   { int mq_notify(l_mqd_t mqd, const struct sigevent *notification); }
+282    STD     LINUX   { int linux_mq_getsetattr(l_mqd_t mqd, const struct mq_attr *attr, \
+                       struct mq_attr *oattr); }
+283    UNIMPL  LINUX   linux_kexec_load
+284    UNIMPL  LINUX   linux_waitid
+285    UNIMPL  LINUX   linux_nonexistant2
+286    UNIMPL  LINUX   linux_add_key
+287    UNIMPL  LINUX   linux_request_key
+288    UNIMPL  LINUX   linux_keyctl
+289    UNIMPL  LINUX   linux_ioprio_set
+290    UNIMPL  LINUX   linux_ioprio_get
+291    UNIMPL  LINUX   linux_inotify_init
+292    UNIMPL  LINUX   linux_inotify_add_watch
+293    UNIMPL  LINUX   linux_inotify_rm_watch
+294    UNIMPL  LINUX   linux_migrate_pages
+295    STD     LINUX   { int linux_openat(l_int dfd, char *path, \
+                                       l_int flags, l_int mode); }
+296    STD     LINUX   { int linux_mkdirat(l_int dfd, char *path, \
+                                       l_int mode); }
+297    STD     LINUX   { int linux_mknodat(l_int dfd, char *path, \
+                                       l_int mode, l_uint dev); }
+298    STD     LINUX   { int linux_fchownat(l_int dfd, char *filename, \
+                                       l_uid16_t uid, l_gid16_t gid, l_int flag); }
+299    STD     LINUX   { int linux_futimesat(l_int dfd, char *fname, \
+                                       struct l_timeval *tptr); }
+300    STD     LINUX   { int linux_fstatat64(l_int dfd, char *path, \
+                                       struct l_stat64 *statbuf, l_int flag); }
+301    STD     LINUX   { int linux_unlinkat(l_int dfd, char *path, \
+                                       l_int flag); }
+302    STD     LINUX   { int linux_renameat(l_int olddfd, char *from, \
+                                       l_int newdfd, char *to); }
+303    STD     LINUX   { int linux_linkat(l_int olddfd, char *path, \
+                                       l_int newdfd, char *to, l_int flags); }
+304    STD     LINUX   { int linux_symlinkat(char *path, l_int newdfd, \
+                                       char *to); }
+305    STD     LINUX   { int linux_readlinkat(l_int dfd, char *path, \
+                                       char *buf, l_int count); }
+306    STD     LINUX   { int linux_fchmodat(l_int dfd, char *filename, \
+                                       l_mode_t mode); }
+307    STD     LINUX   { int linux_faccessat(l_int dfd, char *filename, l_int mode); }
+308    UNIMPL  LINUX   linux_pselect6
+309    UNIMPL  LINUX   linux_ppoll
+310    UNIMPL  LINUX   linux_unshare
+311    STD     LINUX   { int linux_set_robust_list(struct linux_robust_list_head *head, \
+                                       l_size_t len); }
+312    STD     LINUX   { int linux_get_robust_list(l_int pid, struct linux_robust_list_head **head, \
+                                       l_size_t *len); }
+313    UNIMPL  LINUX   linux_splice
+314    UNIMPL  LINUX   linux_sync_file_range
+315    UNIMPL  LINUX   linux_tee
+316    UNIMPL  LINUX   linux_vmsplice
+317    UNIMPL  LINUX   linux_move_pages
+318    STD     LINUX   { int linux_getcpu(l_uint *pcpu, l_uint *pnode, void *ptcache); }
+319    UNIMPL  LINUX   linux_epoll_pwait
+320    STD     LINUX   { int linux_utimensat(l_int dfd, char *fname, \
+                                       struct l_timespec *tptr, l_int flag); }
+321    UNIMPL  LINUX   linux_signalfd
+322    UNIMPL  LINUX   linux_timerfd_create
+323    UNIMPL  LINUX   linux_eventfd
+324    UNIMPL  LINUX   linux_fallocate
+325    UNIMPL  LINUX   linux_timerfd_settime
+326    UNIMPL  LINUX   linux_timerfd_gettime
+327    UNIMPL  LINUX   linux_signalfd4
+328    UNIMPL  LINUX   linux_eventfd2
+329    UNIMPL  LINUX   linux_epoll_create1
+330    UNIMPL  LINUX   linux_dup3
+331    UNIMPL  LINUX   linux_pipe2
+332    UNIMPL  LINUX   linux_inotify_init1
+333    UNIMPL  LINUX   linux_preadv
+334    UNIMPL  LINUX   linux_pwritev
+335    UNIMPL  LINUX   linux_rt_tgsigqueueinfo
+336    UNIMPL  LINUX   linux_perf_event_open
+337    UNIMPL  LINUX   linux_recvmmsg
diff --git a/sys/emulation/linux/linux_emuldata.c b/sys/emulation/linux/linux_emuldata.c
new file mode 100644 (file)
index 0000000..56f57b8
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Alex Hornung <ahornung@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/imgact_aout.h>
+#include <sys/imgact_elf.h>
+#include <sys/kern_syscall.h>
+#include <sys/lock.h>
+#include <sys/mplock2.h>
+#include <sys/malloc.h>
+#include <sys/ptrace.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <sys/exec.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/cpu.h>
+
+#include "i386/linux.h"
+#include "i386/linux_proto.h"
+#include "linux_signal.h"
+#include "linux_util.h"
+#include "linux_emuldata.h"
+
+
+struct lock emul_lock;
+
+struct linux_emuldata *
+emuldata_get(struct proc *p)
+{
+       struct linux_emuldata *em;
+
+       EMUL_LOCK();
+
+       em = p->p_emuldata;
+
+       EMUL_UNLOCK();
+       return (em);
+}
+
+void
+emuldata_set_robust(struct proc *p, struct linux_robust_list_head *robust_ftx)
+{
+       struct linux_emuldata *em;
+
+       EMUL_LOCK();
+
+       em = emuldata_get(p);
+       KKASSERT(em != NULL);
+
+       em->robust_futexes = robust_ftx;
+       EMUL_UNLOCK();
+}
+
+int
+emuldata_init(struct proc *p, struct proc *pchild, int flags)
+{
+       struct linux_emuldata_shared *s;
+       struct linux_emuldata *em, *ep;
+       int error = 0;
+
+       EMUL_LOCK();
+
+       em = emuldata_get(p);
+
+       if (pchild == NULL) {
+               ep = NULL;
+               /* This is the execv* case, where a process gets overwritten */
+               KKASSERT(em != NULL);
+               KKASSERT(em->s != NULL);
+               if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
+                       kfree(em->s, M_LINUX); 
+                       em->s = NULL;
+               }
+               if (em->s)
+                       KKASSERT(em->s->refs >= 0);
+               
+               em->parent_tidptr = NULL;
+               em->child_tidptr = NULL;
+               em->clone_flags = 0;
+               em->clear_tid = NULL;
+               em->set_tls = NULL;
+               em->proc = p;
+       } else {
+               ep = em;
+               em = kmalloc(sizeof(*em), M_LINUX, M_WAITOK | M_ZERO);
+       }
+
+       if (flags & LINUX_CLONE_THREAD) {
+               /*
+                * If CLONE_THREAD is set, the child is placed in the same
+                * thread group as the calling process.
+                */
+               KKASSERT(ep != NULL);
+               em->s = ep->s;
+               s = em->s;
+       } else {
+               /* new thread group */
+               s = kmalloc(sizeof(*s), M_LINUX, M_WAITOK | M_ZERO);
+               LIST_INIT(&s->threads);
+               if (pchild)
+                       s->group_pid = pchild->p_pid;
+               else
+                       s->group_pid = p->p_pid;
+       }
+
+       if (ep != NULL) {
+               em->parent_tidptr = ep->parent_tidptr;
+               em->child_tidptr = ep->child_tidptr;
+#if 0
+               em->clone_flags = ep->clone_flags;
+#endif
+       }
+
+       em->clone_flags = flags;
+
+       atomic_add_int(&s->refs, 1);
+       KKASSERT(s->refs >= 0);
+       em->s = s;
+       LIST_INSERT_HEAD(&s->threads, em, threads);
+
+       
+       if (pchild != NULL) {
+               em->proc = pchild;
+               pchild->p_emuldata = em;
+       }
+
+       EMUL_UNLOCK();
+       return (error);
+}
+
+/* emuldata_exit is modelled after NetBSD's */
+void
+emuldata_exit(void *unused, struct proc *p)
+{
+       struct linux_sys_futex_args cup;
+       struct linux_emuldata *em;
+       int error = 0;
+
+       if (__predict_true(p->p_sysent != &elf_linux_sysvec))
+               return;
+
+       release_futexes(p);
+       EMUL_LOCK();
+
+       em = emuldata_get(p);
+       if (em == NULL) {
+               EMUL_UNLOCK();
+               return;
+       }
+
+       /*
+        * Members of the thread groups others than the leader should
+        * exit quietely: no zombie stage, no signal. We do that by
+        * reparenting to init. init will collect us and nobody will
+        * notice what happened.
+        */
+       if ((em->s->group_pid != p->p_pid) &&
+           (em->clone_flags & LINUX_CLONE_THREAD)) {
+               p->p_sigparent = SIGCHLD;
+
+               wakeup((caddr_t) initproc); /* kern_exit seems to do this */
+               proc_reparent(p, initproc); /* XXX: might be dangerous */
+       }
+
+       if (em->clear_tid != NULL) {
+               int tid = 0;
+               copyout(&tid, em->clear_tid, sizeof(tid));
+               cup.uaddr = em->clear_tid;
+               cup.op = LINUX_FUTEX_WAKE;
+               cup.val = 0x7fffffff;   /* Awake everyone */
+               cup.timeout = NULL;
+               cup.uaddr2 = NULL;
+               cup.val3 = 0;
+               error = sys_linux_sys_futex(&cup);
+               if (error)
+                       kprintf("emuldata_exit futex stuff failed miserably\n");
+       }
+
+       LIST_REMOVE(em, threads);
+
+       p->p_emuldata = NULL;
+
+       if ((em->s->group_pid == p->p_pid) &&
+           (em->s->flags & LINUX_LES_INEXITGROUP)) {
+               p->p_xstat = em->s->xstat;
+       }
+
+       if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
+               kfree(em->s, M_LINUX);
+               em->s = NULL;
+       }
+       if (em->s)
+               KKASSERT(em->s->refs >= 0);
+
+       EMUL_UNLOCK();
+       kfree(em, M_LINUX);
+}
+
+void
+linux_proc_transition(void *unused, struct image_params *imgp)
+{
+       struct proc *p;
+
+       p = imgp->proc;
+       if (__predict_false(imgp->proc->p_sysent == &elf_linux_sysvec &&
+           imgp->proc->p_emuldata == NULL)) {
+#ifdef LINUX_DEBUG
+               kprintf("timidly hello from proc_transition\n");
+#endif
+               emuldata_init(p, p, 0);
+       }
+}
+
+static void
+linux_proc_userret(void)
+{
+       struct proc *p = curproc;
+       struct linux_emuldata *em;
+
+       em = emuldata_get(p);
+       KKASSERT(em != NULL);
+
+       if (em->clone_flags & LINUX_CLONE_CHILD_SETTID) {
+               copyout(&p->p_pid, (int *)em->child_tidptr,
+                   sizeof(p->p_pid));
+       }
+
+       return;
+}
+
+void
+linux_proc_fork(struct proc *p, struct proc *parent, void *child_tidptr)
+{
+       struct linux_emuldata *em;
+
+       em = emuldata_get(p);
+       KKASSERT(em != NULL);
+
+       if (child_tidptr != NULL)
+               em->child_tidptr = child_tidptr;
+
+       /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
+       if (em->clone_flags & LINUX_CLONE_CHILD_CLEARTID)
+               em->clear_tid = em->child_tidptr;
+
+       if (em->clone_flags & LINUX_CLONE_CHILD_SETTID)
+               p->p_userret = linux_proc_userret;
+
+       return;
+}
+
+int
+sys_linux_set_tid_address(struct linux_set_tid_address_args *args)
+{
+       struct linux_emuldata *em;
+
+       EMUL_LOCK();
+
+       em = emuldata_get(curproc);
+       KKASSERT(em != NULL);
+
+       em->clear_tid = args->tidptr;
+       args->sysmsg_iresult = curproc->p_pid;
+
+       EMUL_UNLOCK();
+       return 0;
+}
diff --git a/sys/emulation/linux/linux_emuldata.h b/sys/emulation/linux/linux_emuldata.h
new file mode 100644 (file)
index 0000000..e976114
--- /dev/null
@@ -0,0 +1,110 @@
+/*     $NetBSD: linux_emuldata.h,v 1.16 2008/10/26 16:38:22 christos Exp $     */
+
+/*-
+ * Copyright (c) 1998,2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Eric Haszlakiewicz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "linux_futex.h"
+
+#ifndef _SYS_LOCK_H
+#include <sys/lock.h>
+#endif
+
+#ifndef _SYS_MPLOCK2_H
+#include <sys/mplock2.h>
+#endif
+
+#ifndef _COMMON_LINUX_EMULDATA_H
+#define _COMMON_LINUX_EMULDATA_H
+
+/*
+ * This is auxillary data the linux compat code
+ * needs to do its work.  A pointer to it is
+ * stored in the emuldata field of the proc
+ * structure.
+ */
+struct linux_emuldata_shared {
+       void *  p_break;        /* Processes' idea of break */
+       int refs;
+       pid_t group_pid;        /* PID of Linux process (group of threads) */
+       /* List of Linux threads (NetBSD processes) in the Linux process */
+       LIST_HEAD(, linux_emuldata) threads;
+       int flags;              /* See below */
+       int xstat;              /* Thread group exit code, for exit_group */
+};
+
+#define LINUX_LES_INEXITGROUP  0x1     /* thread group doing exit_group() */
+#define LINUX_LES_USE_NPTL     0x2     /* Need to emulate NPTL threads */
+
+struct linux_emuldata {
+#if notyet
+       sigset_t ps_siginfo;    /* Which signals have a RT handler */
+#endif
+       int     debugreg[8];    /* GDB information for ptrace - for use, */
+                               /* see ../arch/i386/linux_ptrace.c */
+       struct linux_emuldata_shared *s;
+
+       void *parent_tidptr;    /* Used during clone() */
+       void *child_tidptr;     /* Used during clone() */
+       int clone_flags;        /* Used during clone() */
+       int flags;
+       void *clear_tid;        /* Own TID to clear on exit */
+       void *set_tls;          /* Pointer to child TLS desc in user space */
+
+       struct linux_robust_list_head *robust_futexes;
+
+       /* List of Linux threads (NetBSD processes) in the Linux process */
+       LIST_ENTRY(linux_emuldata) threads;
+       struct proc *proc;      /* backpointer to struct proc */
+};
+
+#define        EMUL_DIDKILL    0x01
+
+#define LINUX_CHILD_QUIETEXIT  0x1     /* Child will have quietexit set */
+#define LINUX_QUIETEXIT                0x2     /* Quiet exit (no zombie state) */
+
+#define        EMUL_LOCKINIT(x)        lockinit(&emul_lock, "tux_emul", 0, LK_CANRECURSE)
+#define        EMUL_LOCKUNINIT(x)      lockuninit(&emul_lock)
+
+#if 0
+#define EMUL_LOCK(x)   lockmgr(&emul_lock, LK_EXCLUSIVE)
+#define        EMUL_UNLOCK(x)  lockmgr(&emul_lock, LK_RELEASE)
+#endif
+
+#define EMUL_LOCK(x)   get_mplock()
+#define        EMUL_UNLOCK(x)  rel_mplock()
+
+extern struct lock emul_lock;
+
+struct linux_emuldata *emuldata_get(struct proc *p);
+void   emuldata_set_robust(struct proc *p, struct linux_robust_list_head *robust_ftx);
+int    emuldata_init(struct proc *p, struct proc *pchild, int flags);
+void   emuldata_exit(void *unused, struct proc *p);
+void   linux_proc_transition(void *unused, struct image_params *imgp);
+void   linux_proc_fork(struct proc *p, struct proc *parent, void *child_tidptr);
+#endif /* !_COMMON_LINUX_EMULDATA_H */
diff --git a/sys/emulation/linux/linux_epoll.c b/sys/emulation/linux/linux_epoll.c
new file mode 100644 (file)
index 0000000..9e8cd74
--- /dev/null
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kern_syscall.h>
+#include <sys/event.h>
+#include <sys/lock.h>
+#include <sys/mplock2.h>
+#include <sys/malloc.h>
+#include <sys/ptrace.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <sys/exec.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/cpu.h>
+
+#include "i386/linux.h"
+#include "i386/linux_proto.h"
+#include "linux_signal.h"
+#include "linux_util.h"
+#include "linux_epoll.h"
+
+
+/* Create a new epoll file descriptor. */
+int
+sys_linux_epoll_create(struct linux_epoll_create_args *args)
+{
+        struct kqueue_args k_args;
+
+        if (args->size <= 0)
+                return (EINVAL);
+        /* args->size is unused. Linux ignores it as well. */
+
+        return (sys_kqueue(&k_args));
+}
+
+/* Structure converting function from epoll to kevent. */
+static void
+linux_epoll_to_kevent(int fd, struct linux_epoll_event *event, struct kevent *kevent)
+{
+        int filter = 0;
+        int flags = kevent->flags;
+
+        if (event->events & LINUX_EPOLLIN)
+                filter |= EVFILT_READ;
+        if (event->events & LINUX_EPOLLOUT)
+                filter |= EVFILT_WRITE;
+        if (event->events & LINUX_EPOLLPRI)
+                filter |= EVFILT_READ;
+        if (event->events & LINUX_EPOLLET)
+                flags |= EV_CLEAR;
+        if (event->events & LINUX_EPOLLONESHOT)
+                flags |= EV_ONESHOT;
+
+        EV_SET(kevent, fd, filter, flags, 0, 0, NULL);
+}
+
+/*
+ * Structure converting function from kevent to epoll. In a case
+ * this is called on error in registration we store the error in
+ * event->data and pick it up later in linux_epoll_ctl().
+ */
+static void
+linux_kevent_to_epoll(struct kevent *kevent, struct linux_epoll_event *event)
+{
+        if (kevent->flags & EV_ERROR) {
+                event->data = kevent->data;
+                return;
+        }
+        switch (kevent->filter) {
+                case EVFILT_READ:
+                        if (kevent->data > 0)
+                                event->events = LINUX_EPOLLIN;
+                        event->data = kevent->ident;
+                break;
+                case EVFILT_WRITE:
+                        if (kevent->data > 0)
+                                event->events = LINUX_EPOLLOUT;
+                        event->data = kevent->ident;
+                break;
+        }
+}
+
+/*
+ * Copyout callback used by kevent. This converts kevent
+ * events to epoll events and copies them back to the
+ * userspace. This is also called on error on registering
+ * of the filter.
+ */
+static int
+linux_kev_copyout(void *arg, struct kevent *kevp, int count)
+{
+        struct kevent_args *uap;
+        struct linux_epoll_event *eep;
+        int error, i;
+
+        uap = (struct kevent_args*) arg;
+
+        eep = kmalloc(sizeof(*eep) * count, M_TEMP, M_WAITOK | M_ZERO);
+
+        for (i = 0; i < count; i++) {
+                linux_kevent_to_epoll(&kevp[i], &eep[i]);
+        }
+
+        error = copyout(eep, uap->eventlist, count * sizeof(*eep));
+        if (error)
+                uap->eventlist = (struct kevent *)((char *)uap->eventlist + count * sizeof(*eep));
+
+        kfree(eep, M_TEMP);
+        return (0);
+}
+
+/*
+ * Copyin callback used by kevent. This copies already
+ * converted filters to the kevent internal memory.
+ */
+static int
+linux_kev_copyin(void *arg, struct kevent *kevp, int count)
+{
+        struct kevent_args *uap;
+
+        uap = (struct kevent_args*) arg;
+
+        memcpy(kevp, uap->changelist, count * sizeof(*kevp));
+
+        uap->changelist += count;
+
+        return (0);
+}
+
+/*
+ * Load epoll filter, convert it to kevent filter
+ * and load it into kevent subsystem.
+ */
+int
+sys_linux_epoll_ctl(struct linux_epoll_ctl_args *args)
+{
+        struct kevent_args k_args;
+        struct kevent kev;
+        struct linux_epoll_event le;
+        int error;
+
+        error = copyin(args->event, &le, sizeof(le));
+        if (error)
+                return (error);
+#ifdef DEBUG
+        if (ldebug(epoll_ctl))
+                kprintf(ARGS(epoll_ctl,"%i, %i, %i, %u"), args->epfd, args->op,
+                        args->fd, le.events);
+#endif
+        k_args.fd = args->epfd;
+        k_args.changelist = &kev;
+        /* The epoll can register only 1 filter at once. */
+        k_args.nchanges = 1;
+        k_args.eventlist = NULL;
+        k_args.nevents = 0;
+        k_args.timeout = NULL;
+
+        switch (args->op) {
+        case LINUX_EPOLL_CTL_ADD:
+                        kev.flags = EV_ADD | EV_ENABLE;
+                break;
+        case LINUX_EPOLL_CTL_MOD:
+                        /* TODO: DELETE && ADD maybe? */
+                        return (EINVAL);
+                break;
+        case LINUX_EPOLL_CTL_DEL:
+                        kev.flags = EV_DELETE | EV_DISABLE;
+                break;
+        }
+        linux_epoll_to_kevent(args->fd, &le, &kev);
+
+       error = kern_kevent(args->epfd, 1, 0, &k_args, linux_kev_copyin,
+           linux_kev_copyout, NULL);
+        /* Check if there was an error during registration. */
+        if (error == 0 && k_args.sysmsg_result != 0) {
+                /* The copyout callback stored the error there. */
+                error = le.data;
+        }
+
+        return (error);
+}
+
+/*
+ * Wait for a filter to be triggered on the epoll file descriptor. */
+int
+sys_linux_epoll_wait(struct linux_epoll_wait_args *args)
+{
+        struct timespec ts;
+        struct kevent_args k_args;
+        int error;
+
+        /* Convert from miliseconds to timespec. */
+        ts.tv_sec = args->timeout / 1000000;
+        ts.tv_nsec = (args->timeout % 1000000) * 1000;
+
+        k_args.fd = args->epfd;
+        k_args.changelist = NULL;
+        k_args.nchanges = 0;
+        /*
+         * We don't mind the bogus type-cast because
+         * our copyout function knows about this and
+         * handles it correctly.
+         */
+        k_args.eventlist = (struct kevent *)args->events;
+        k_args.nevents = args->maxevents;
+        k_args.timeout = &ts;
+
+       error = kern_kevent(args->epfd, 0, args->maxevents, &k_args,
+           linux_kev_copyin, linux_kev_copyout, &ts);
+
+        /* translation? */
+        return (error);
+}
diff --git a/sys/emulation/linux/linux_epoll.h b/sys/emulation/linux/linux_epoll.h
new file mode 100644 (file)
index 0000000..37cd3eb
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2007 Roman Divacky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_EPOLL_H_
+#define _LINUX_EPOLL_H_
+
+#ifdef __amd64__
+#define EPOLL_PACKED    __packed
+#else
+#define EPOLL_PACKED
+#endif
+
+struct linux_epoll_event {
+        uint32_t        events;
+        uint64_t        data;
+} EPOLL_PACKED;
+
+#define LINUX_EPOLLIN           0x001
+#define LINUX_EPOLLPRI          0x002
+#define LINUX_EPOLLOUT          0x004
+#define LINUX_EPOLLONESHOT      (1 << 30)
+#define LINUX_EPOLLET           (1 << 31)
+
+#define LINUX_EPOLL_CTL_ADD     1
+#define LINUX_EPOLL_CTL_DEL     2
+#define LINUX_EPOLL_CTL_MOD     3
+
+#define LINUX_MAX_EVENTS        (INT_MAX / sizeof(struct linux_epoll_event))
+
+#endif  /* !_LINUX_EPOLL_H_ */
index 16c3ede..bb0ba0a 100644 (file)
@@ -145,6 +145,89 @@ sys_linux_open(struct linux_open_args *args)
                error = kern_open(&nd, flags,
                                  args->mode, &args->sysmsg_iresult);
        }
+       nlookup_done(&nd);
+
+       if (error == 0 && !(flags & O_NOCTTY) && 
+               SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
+               struct file *fp;
+
+               fp = holdfp(p->p_fd, args->sysmsg_iresult, -1);
+               if (fp) {
+                       if (fp->f_type == DTYPE_VNODE) {
+                               fo_ioctl(fp, TIOCSCTTY, NULL,
+                                        td->td_ucred, NULL);
+                       }
+                       fdrop(fp);
+               }
+       }
+       rel_mplock();
+#ifdef DEBUG
+       if (ldebug(open))
+               kprintf(LMSG("open returns error %d"), error);
+#endif
+       linux_free_path(&path);
+       return error;
+}
+
+int
+sys_linux_openat(struct linux_openat_args *args)
+{
+       struct thread *td = curthread;
+       struct proc *p = td->td_proc;
+       struct nlookupdata nd;
+       struct file *fp;
+       char *path;
+       int error, flags, dfd;
+
+       if (args->flags & LINUX_O_CREAT) {
+               error = linux_copyin_path(args->path, &path,
+                   LINUX_PATH_CREATE);
+       } else {
+               error = linux_copyin_path(args->path, &path,
+                   LINUX_PATH_EXISTS);
+       }
+       if (error)
+               return (error);
+
+#ifdef DEBUG
+       if (ldebug(open))
+               kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
+                   args->mode);
+#endif
+       flags = 0;
+       if (args->flags & LINUX_O_RDONLY)
+               flags |= O_RDONLY;
+       if (args->flags & LINUX_O_WRONLY)
+               flags |= O_WRONLY;
+       if (args->flags & LINUX_O_RDWR)
+               flags |= O_RDWR;
+       if (args->flags & LINUX_O_NDELAY)
+               flags |= O_NONBLOCK;
+       if (args->flags & LINUX_O_APPEND)
+               flags |= O_APPEND;
+       if (args->flags & LINUX_O_SYNC)
+               flags |= O_FSYNC;
+       if (args->flags & LINUX_O_NONBLOCK)
+               flags |= O_NONBLOCK;
+       if (args->flags & LINUX_FASYNC)
+               flags |= O_ASYNC;
+       if (args->flags & LINUX_O_CREAT)
+               flags |= O_CREAT;
+       if (args->flags & LINUX_O_TRUNC)
+               flags |= O_TRUNC;
+       if (args->flags & LINUX_O_EXCL)
+               flags |= O_EXCL;
+       if (args->flags & LINUX_O_NOCTTY)
+               flags |= O_NOCTTY;
+
+       dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       get_mplock();
+       error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = kern_open(&nd, flags,
+                                 args->mode, &args->sysmsg_iresult);
+       }
+       nlookup_done_at(&nd, fp);
 
        if (error == 0 && !(flags & O_NOCTTY) && 
                SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
@@ -414,7 +497,7 @@ again:
                        error = copyout(&linux_dirent, outp, linuxreclen);
                } else {
                        if (is64bit) {
-                               linux_dirent64.d_ino = bdp->d_ino;
+                               linux_dirent64.d_ino = INO64TO32(bdp->d_ino);
                                linux_dirent64.d_off = (cookiep)
                                    ? (l_off_t)*cookiep
                                    : (l_off_t)(off + reclen);
@@ -557,6 +640,42 @@ sys_linux_unlink(struct linux_unlink_args *args)
        return(error);
 }
 
+int
+sys_linux_unlinkat(struct linux_unlinkat_args *args)
+{
+       struct nlookupdata nd;
+       struct file *fp;
+       char *path;
+       int dfd, error;
+
+       if (args->flag & ~LINUX_AT_REMOVEDIR)
+               return (EINVAL);
+
+       error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
+       if (error) {
+               kprintf("linux_copyin_path says error = %d\n", error);
+               return (error);
+       }
+#ifdef DEBUG
+       if (ldebug(unlink))
+               kprintf(ARGS(unlink, "%s"), path);
+#endif
+
+       dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       get_mplock();
+       error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               if (args->flag & LINUX_AT_REMOVEDIR)
+                       error = kern_rmdir(&nd);
+               else
+                       error = kern_unlink(&nd);
+       }
+       nlookup_done_at(&nd, fp);
+       rel_mplock();
+       linux_free_path(&path);
+       return(error);
+}
+
 /*
  * MPALMOSTSAFE
  */
@@ -640,6 +759,33 @@ sys_linux_mkdir(struct linux_mkdir_args *args)
        return(error);
 }
 
+int
+sys_linux_mkdirat(struct linux_mkdirat_args *args)
+{
+       struct nlookupdata nd;
+       struct file *fp;
+       char *path;
+       int dfd, error;
+
+       error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
+       if (error)
+               return (error);
+#ifdef DEBUG
+       if (ldebug(mkdir))
+               kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
+#endif
+       dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       get_mplock();
+       error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
+       if (error == 0)
+               error = kern_mkdir(&nd, args->mode);
+       nlookup_done_at(&nd, fp);
+       rel_mplock();
+
+       linux_free_path(&path);
+       return(error);
+}
+
 /*
  * MPALMOSTSAFE
  */
@@ -704,6 +850,43 @@ sys_linux_rename(struct linux_rename_args *args)
        return(error);
 }
 
+int
+sys_linux_renameat(struct linux_renameat_args *args)
+{
+       struct nlookupdata fromnd, tond;
+       struct file *fp, *fp2;
+       char *from, *to;
+       int olddfd, newdfd,error;
+
+       error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
+       if (error)
+               return (error);
+       error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
+       if (error) {
+               linux_free_path(&from);
+               return (error);
+       }
+#ifdef DEBUG
+       if (ldebug(rename))
+               kprintf(ARGS(rename, "%s, %s"), from, to);
+#endif
+       olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
+       newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
+       get_mplock();
+       error = nlookup_init_at(&fromnd, &fp, olddfd, from, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               error = nlookup_init_at(&tond, &fp2, newdfd, to, UIO_SYSSPACE, 0);
+               if (error == 0)
+                       error = kern_rename(&fromnd, &tond);
+               nlookup_done_at(&tond, fp2);
+       }
+       nlookup_done_at(&fromnd, fp);
+       rel_mplock();
+       linux_free_path(&from);
+       linux_free_path(&to);
+       return(error);
+}
+
 /*
  * MPALMOSTSAFE
  */
@@ -741,6 +924,42 @@ sys_linux_symlink(struct linux_symlink_args *args)
        return(error);
 }
 
+int
+sys_linux_symlinkat(struct linux_symlinkat_args *args)
+{
+       struct thread *td = curthread;
+       struct nlookupdata nd;
+       struct file *fp;
+       char *path, *link;
+       int error;
+       int newdfd, mode;
+
+       error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
+       if (error)
+               return (error);
+       error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
+       if (error) {
+               linux_free_path(&path);
+               return (error);
+       }
+#ifdef DEBUG
+       if (ldebug(symlink))
+               kprintf(ARGS(symlink, "%s, %s"), path, link);
+#endif
+       newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
+       get_mplock();
+       error = nlookup_init_at(&nd, &fp, newdfd, link, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
+               error = kern_symlink(&nd, path, mode);
+       }
+       nlookup_done_at(&nd, fp);
+       rel_mplock();
+       linux_free_path(&path);
+       linux_free_path(&link);
+       return(error);
+}
+
 /*
  * MPALMOSTSAFE
  */
@@ -771,6 +990,35 @@ sys_linux_readlink(struct linux_readlink_args *args)
        return(error);
 }
 
+int
+sys_linux_readlinkat(struct linux_readlinkat_args *args)
+{
+       struct nlookupdata nd;
+       struct file *fp;
+       char *path;
+       int dfd, error;
+
+       error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
+       if (error)
+               return (error);
+#ifdef DEBUG
+       if (ldebug(readlink))
+               kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
+                   args->count);
+#endif
+       dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       get_mplock();
+       error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               error = kern_readlink(&nd, args->buf, args->count,
+                                     &args->sysmsg_iresult);
+       }
+       nlookup_done_at(&nd, fp);
+       rel_mplock();
+       linux_free_path(&path);
+       return(error);
+}
+
 /*
  * MPALMOSTSAFE
  */
@@ -904,6 +1152,46 @@ sys_linux_link(struct linux_link_args *args)
        return(error);
 }
 
+int
+sys_linux_linkat(struct linux_linkat_args *args)
+{
+       struct nlookupdata nd, linknd;
+       struct file *fp, *fp2;
+       char *path, *link;
+       int olddfd, newdfd, error;
+
+       if (args->flags != 0)
+               return (EINVAL);
+
+       error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
+       if (error)
+               return (error);
+       error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
+       if (error) {
+               linux_free_path(&path);
+               return (error);
+       }
+#ifdef DEBUG
+       if (ldebug(link))
+               kprintf(ARGS(link, "%s, %s"), path, link);
+#endif
+       olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
+       newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
+       get_mplock();
+       error = nlookup_init_at(&nd, &fp, olddfd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       if (error == 0) {
+               error = nlookup_init_at(&linknd, &fp2, newdfd, link, UIO_SYSSPACE, 0);
+               if (error == 0)
+                       error = kern_link(&nd, &linknd);
+               nlookup_done_at(&linknd, fp2);
+       }
+       nlookup_done_at(&nd, fp);
+       rel_mplock();
+       linux_free_path(&path);
+       linux_free_path(&link);
+       return(error);
+}
+
 /*
  * MPSAFE
  */
@@ -1386,3 +1674,55 @@ sys_linux_lchown(struct linux_lchown_args *args)
        return(error);
 }
 
+int
+sys_linux_fchmodat(struct linux_fchmodat_args *args)
+{
+       struct fchmodat_args uap;
+       int error;
+
+       uap.fd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       uap.path = args->filename;
+       uap.mode = args->mode;
+       uap.flags = 0;
+
+       error = sys_fchmodat(&uap);
+
+       return (error);
+}
+
+int
+sys_linux_fchownat(struct linux_fchownat_args *args)
+{
+       struct fchownat_args uap;
+       int error;
+
+       if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
+               return (EINVAL);
+
+       uap.fd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       uap.path = args->filename;
+       uap.uid = args->uid;
+       uap.gid = args->gid;
+       uap.flags = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
+           AT_SYMLINK_NOFOLLOW;
+
+       error = sys_fchownat(&uap);
+
+       return (error);
+}
+
+int
+sys_linux_faccessat(struct linux_faccessat_args *args)
+{
+       struct faccessat_args uap;
+       int error;
+
+       uap.fd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       uap.path = args->filename;
+       uap.amode = args->mode;
+       uap.flags = 0;
+
+       error = sys_faccessat(&uap);
+
+       return error;
+}
diff --git a/sys/emulation/linux/linux_futex.c b/sys/emulation/linux/linux_futex.c
new file mode 100644 (file)
index 0000000..c4cf129
--- /dev/null
@@ -0,0 +1,856 @@
+/*     $NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $ */
+
+/*-
+ * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Emmanuel Dreyfus
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/imgact_aout.h>
+#include <sys/imgact_elf.h>
+#include <sys/kern_syscall.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/priv.h>
+#include <sys/lock.h>
+#include <sys/spinlock2.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <sys/exec.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/cpu.h>
+#include <machine/limits.h>
+
+#include "i386/linux.h"
+#include "i386/linux_proto.h"
+#include "linux_signal.h"
+#include "linux_util.h"
+#include "linux_emuldata.h"
+
+MALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes");
+MALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futexes wp");
+
+struct futex;
+
+struct waiting_proc {
+       uint32_t        wp_flags;
+       struct futex    *wp_futex;
+       TAILQ_ENTRY(waiting_proc) wp_list;
+};
+
+struct futex {
+       struct lock     f_lck;
+       uint32_t        *f_uaddr;
+       uint32_t        f_refcount;
+       LIST_ENTRY(futex) f_list;
+       TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc;
+};
+
+struct futex_list futex_list;
+
+#if 0
+#define FUTEX_LOCK(f)          spin_lock_wr(&(f)->f_lck)
+#define FUTEX_UNLOCK(f)                spin_unlock_wr(&(f)->f_lck)
+#define FUTEX_INIT(f)          spin_init(&(f)->f_lck)
+#define        FUTEX_SLEEP(f, id, flag, wm, timo)      ssleep((id), &(f)->f_lck, (flag), (wm), (timo))
+#endif
+
+#define FUTEX_LOCK(f)          lockmgr(&(f)->f_lck, LK_EXCLUSIVE)
+#define FUTEX_UNLOCK(f)                lockmgr(&(f)->f_lck, LK_RELEASE)
+#define FUTEX_INIT(f)          lockinit(&(f)->f_lck, "ftlk", 0, LK_CANRECURSE)
+#define FUTEX_DESTROY(f)       lockuninit(&(f)->f_lck)
+#define FUTEX_ASSERT_LOCKED(f) KKASSERT(lockstatus(&(f)->f_lck, curthread) == LK_EXCLUSIVE)
+#define        FUTEX_SLEEP(f, id, flag, wm, timo)      lksleep((id), &(f)->f_lck, (flag), (wm), (timo))
+
+struct lock futex_mtx;                 /* protects the futex list */
+#define FUTEXES_LOCK           lockmgr(&futex_mtx, LK_EXCLUSIVE)
+#define FUTEXES_UNLOCK         lockmgr(&futex_mtx, LK_RELEASE)
+
+/* Debug magic to take advantage of freebsd's mess */
+#if LINUX_DEBUG
+#define LINUX_CTR_PREFIX
+#else
+#define LINUX_CTR_PREFIX       while (0)
+#endif
+
+#define LINUX_CTR1(a,b,c)      LINUX_CTR_PREFIX kprintf("linux_futex: " b "\n",c)
+#define LINUX_CTR2(a,b,c,d)    LINUX_CTR_PREFIX kprintf("linux_futex: " b "\n",c,d)
+#define LINUX_CTR3(a,b,c,d,e)  LINUX_CTR_PREFIX kprintf("linux_futex: " b "\n",c,d,e)
+#define LINUX_CTR4(a,b,c,d,e,f)        LINUX_CTR_PREFIX kprintf("linux_futex: " b "\n",c,d,e,f)
+#define LINUX_CTR5(a,b,c,d,e,f,g)      LINUX_CTR_PREFIX kprintf("linux_futex: " b "\n",c,d,e,f,g)
+
+
+
+/* flags for futex_get() */
+#define FUTEX_CREATE_WP                0x1     /* create waiting_proc */
+#define FUTEX_DONTCREATE       0x2     /* don't create futex if not exists */
+#define FUTEX_DONTEXISTS       0x4     /* return EINVAL if futex exists */
+
+/* wp_flags */
+#define FUTEX_WP_REQUEUED      0x1     /* wp requeued - wp moved from wp_list
+                                        * of futex where thread sleep to wp_list
+                                        * of another futex.
+                                        */
+#define FUTEX_WP_REMOVED       0x2     /* wp is woken up and removed from futex
+                                        * wp_list to prevent double wakeup.
+                                        */
+
+/* support.s */
+int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_addl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_orl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_andl(int oparg, uint32_t *uaddr, int *oldval);
+int futex_xorl(int oparg, uint32_t *uaddr, int *oldval);
+
+static void
+futex_put(struct futex *f, struct waiting_proc *wp)
+{
+       FUTEX_ASSERT_LOCKED(f);
+       if (wp != NULL) {
+               if ((wp->wp_flags & FUTEX_WP_REMOVED) == 0)
+                       TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+               kfree(wp, M_FUTEX_WP);
+       }
+
+       FUTEXES_LOCK;
+       if (--f->f_refcount == 0) {
+               LIST_REMOVE(f, f_list);
+               FUTEXES_UNLOCK;
+               FUTEX_UNLOCK(f);
+
+               LINUX_CTR2(sys_futex, "futex_put destroy uaddr %p ref %d",
+                   f->f_uaddr, f->f_refcount);
+               FUTEX_DESTROY(f);
+               kfree(f, M_FUTEX);
+               return;
+       }
+
+       LINUX_CTR2(sys_futex, "futex_put uaddr %p ref %d",
+           f->f_uaddr, f->f_refcount);
+       FUTEXES_UNLOCK;
+       FUTEX_UNLOCK(f);
+}
+
+static int
+futex_get0(uint32_t *uaddr, struct futex **newf, uint32_t flags)
+{
+       struct futex *f, *tmpf;
+
+       *newf = tmpf = NULL;
+
+retry:
+       FUTEXES_LOCK;
+       LIST_FOREACH(f, &futex_list, f_list) {
+               if (f->f_uaddr == uaddr) {
+                       if (tmpf != NULL) {
+                               FUTEX_UNLOCK(tmpf);
+                               FUTEX_DESTROY(tmpf);
+                               kfree(tmpf, M_FUTEX);
+                       }
+                       if (flags & FUTEX_DONTEXISTS) {
+                               FUTEXES_UNLOCK;
+                               return (EINVAL);
+                       }
+
+                       /*
+                        * Increment refcount of the found futex to
+                        * prevent it from deallocation before FUTEX_LOCK()
+                        */
+                       ++f->f_refcount;
+                       FUTEXES_UNLOCK;
+
+                       FUTEX_LOCK(f);
+                       *newf = f;
+                       LINUX_CTR2(sys_futex, "futex_get uaddr %p ref %d",
+                           uaddr, f->f_refcount);
+                       return (0);
+               }
+       }
+
+       if (flags & FUTEX_DONTCREATE) {
+               FUTEXES_UNLOCK;
+               LINUX_CTR1(sys_futex, "futex_get uaddr %p null", uaddr);
+               return (0);
+       }
+
+       if (tmpf == NULL) {
+               FUTEXES_UNLOCK;
+               tmpf = kmalloc(sizeof(*tmpf), M_FUTEX, M_WAITOK | M_ZERO);
+               tmpf->f_uaddr = uaddr;
+               tmpf->f_refcount = 1;
+               FUTEX_INIT(tmpf);
+               TAILQ_INIT(&tmpf->f_waiting_proc);
+
+               /*
+                * Lock the new futex before an insert into the futex_list
+                * to prevent futex usage by other.
+                */
+               FUTEX_LOCK(tmpf);
+               goto retry;
+       }
+
+       LIST_INSERT_HEAD(&futex_list, tmpf, f_list);
+       FUTEXES_UNLOCK;
+
+       LINUX_CTR2(sys_futex, "futex_get uaddr %p ref %d new",
+           uaddr, tmpf->f_refcount);
+       *newf = tmpf;
+       return (0);
+}
+
+static int
+futex_get(uint32_t *uaddr, struct waiting_proc **wp, struct futex **f,
+    uint32_t flags)
+{
+       int error;
+
+       if (flags & FUTEX_CREATE_WP) {
+               *wp = kmalloc(sizeof(struct waiting_proc), M_FUTEX_WP, M_WAITOK);
+               (*wp)->wp_flags = 0;
+       }
+       error = futex_get0(uaddr, f, flags);
+       if (error) {
+               if (flags & FUTEX_CREATE_WP) {
+                       kfree(*wp, M_FUTEX_WP);
+                       *wp = NULL;
+               }
+               return (error);
+       }
+       if (flags & FUTEX_CREATE_WP) {
+               TAILQ_INSERT_HEAD(&(*f)->f_waiting_proc, *wp, wp_list);
+               (*wp)->wp_futex = *f;
+       }
+
+       return (error);
+}
+
+static int
+futex_sleep(struct futex *f, struct waiting_proc *wp, unsigned long timeout)
+{
+       int error;
+
+       FUTEX_ASSERT_LOCKED(f);
+       LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %ld ref %d",
+           f->f_uaddr, wp, timeout, f->f_refcount);
+       error = FUTEX_SLEEP(f, wp, PCATCH, "futex", timeout);
+#if 0
+       error = ssleep(wp, &f->f_lck, PCATCH, "futex", timeout);
+       error = sx_sleep(wp, &f->f_lck, PCATCH, "futex", timeout);
+#endif 
+       if (wp->wp_flags & FUTEX_WP_REQUEUED) {
+               KASSERT(f != wp->wp_futex, ("futex != wp_futex"));
+               LINUX_CTR5(sys_futex, "futex_sleep out error %d uaddr %p w"
+                   " %p requeued uaddr %p ref %d",
+                   error, f->f_uaddr, wp, wp->wp_futex->f_uaddr,
+                   wp->wp_futex->f_refcount);
+               futex_put(f, NULL);
+               f = wp->wp_futex;
+               FUTEX_LOCK(f);
+       }
+
+       futex_put(f, wp);
+       return (error);
+}
+
+static int
+futex_wake(struct futex *f, int n)
+{
+       struct waiting_proc *wp, *wpt;
+       int count = 0;
+
+       FUTEX_ASSERT_LOCKED(f);
+       TAILQ_FOREACH_MUTABLE(wp, &f->f_waiting_proc, wp_list, wpt) {
+               LINUX_CTR3(sys_futex, "futex_wake uaddr %p wp %p ref %d",
+                   f->f_uaddr, wp, f->f_refcount);
+               wp->wp_flags |= FUTEX_WP_REMOVED;
+               TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+               wakeup_one(wp);
+               if (++count == n)
+                       break;
+       }
+
+       return (count);
+}
+
+static int
+futex_requeue(struct futex *f, int n, struct futex *f2, int n2)
+{
+       struct waiting_proc *wp, *wpt;
+       int count = 0;
+
+       FUTEX_ASSERT_LOCKED(f);
+       FUTEX_ASSERT_LOCKED(f2);
+
+       TAILQ_FOREACH_MUTABLE(wp, &f->f_waiting_proc, wp_list, wpt) {
+               if (++count <= n) {
+                       LINUX_CTR2(sys_futex, "futex_req_wake uaddr %p wp %p",
+                           f->f_uaddr, wp);
+                       wp->wp_flags |= FUTEX_WP_REMOVED;
+                       TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+                       wakeup_one(wp);
+               } else {
+                       LINUX_CTR3(sys_futex, "futex_requeue uaddr %p wp %p to %p",
+                           f->f_uaddr, wp, f2->f_uaddr);
+                       wp->wp_flags |= FUTEX_WP_REQUEUED;
+                       /* Move wp to wp_list of f2 futex */
+                       TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
+                       TAILQ_INSERT_HEAD(&f2->f_waiting_proc, wp, wp_list);
+
+                       /*
+                        * Thread which sleeps on wp after waking should
+                        * acquire f2 lock, so increment refcount of f2 to
+                        * prevent it from premature deallocation.
+                        */
+                       wp->wp_futex = f2;
+                       FUTEXES_LOCK;
+                       ++f2->f_refcount;
+                       FUTEXES_UNLOCK;
+                       if (count - n >= n2)
+                               break;
+               }
+       }
+
+       return (count);
+}
+
+static int
+futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts)
+{
+       struct l_timespec timeout = {0, 0};
+       struct timeval tv = {0, 0};
+       int timeout_hz;
+       int error;
+
+       if (ts != NULL) {
+               error = copyin(ts, &timeout, sizeof(timeout));
+               if (error)
+                       return (error);
+       }
+
+       tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000;
+       timeout_hz = tvtohz_high(&tv);
+
+       if (timeout.tv_sec == 0 && timeout.tv_nsec == 0)
+               timeout_hz = 0;
+
+       /*
+        * If the user process requests a non null timeout,
+        * make sure we do not turn it into an infinite
+        * timeout because timeout_hz gets null.
+        *
+        * We use a minimal timeout of 1/hz. Maybe it would
+        * make sense to just return ETIMEDOUT without sleeping.
+        */
+       if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) &&
+           (timeout_hz == 0))
+               timeout_hz = 1;
+
+       error = futex_sleep(f, wp, timeout_hz);
+       if (error == EWOULDBLOCK)
+               error = ETIMEDOUT;
+
+       return (error);
+}
+
+static int
+futex_atomic_op(struct proc *p, int encoded_op, uint32_t *uaddr)
+{
+       int op = (encoded_op >> 28) & 7;
+       int cmp = (encoded_op >> 24) & 15;
+       int oparg = (encoded_op << 8) >> 20;
+       int cmparg = (encoded_op << 20) >> 20;
+       int oldval = 0, ret;
+
+       if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+               oparg = 1 << oparg;
+
+#ifdef DEBUG
+       if (ldebug(sys_futex))
+               kprintf("futex_atomic_op: op = %d, cmp = %d, oparg = %x, "
+                      "cmparg = %x, uaddr = %p\n",
+                      op, cmp, oparg, cmparg, uaddr);
+#endif
+       /* XXX: linux verifies access here and returns EFAULT */
+
+       switch (op) {
+       case FUTEX_OP_SET:
+               ret = futex_xchgl(oparg, uaddr, &oldval);
+               break;
+       case FUTEX_OP_ADD:
+               ret = futex_addl(oparg, uaddr, &oldval);
+               break;
+       case FUTEX_OP_OR:
+               ret = futex_orl(oparg, uaddr, &oldval);
+               break;
+       case FUTEX_OP_ANDN:
+               ret = futex_andl(~oparg, uaddr, &oldval);
+               break;
+       case FUTEX_OP_XOR:
+               ret = futex_xorl(oparg, uaddr, &oldval);
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
+       if (ret)
+               return (ret);
+
+       switch (cmp) {
+       case FUTEX_OP_CMP_EQ:
+               return (oldval == cmparg);
+       case FUTEX_OP_CMP_NE:
+               return (oldval != cmparg);
+       case FUTEX_OP_CMP_LT:
+               return (oldval < cmparg);
+       case FUTEX_OP_CMP_GE:
+               return (oldval >= cmparg);
+       case FUTEX_OP_CMP_LE:
+               return (oldval <= cmparg);
+       case FUTEX_OP_CMP_GT:
+               return (oldval > cmparg);
+       default:
+               return (-ENOSYS);
+       }
+}
+
+int
+sys_linux_sys_futex(struct linux_sys_futex_args *args)
+{
+       int op_ret, val, ret, nrwake;
+       struct waiting_proc *wp;
+       struct futex *f, *f2;
+       int error = 0;
+
+       /*
+        * Our implementation provides only privates futexes. Most of the apps
+        * should use private futexes but don't claim so. Therefore we treat
+        * all futexes as private by clearing the FUTEX_PRIVATE_FLAG. It works
+        * in most cases (ie. when futexes are not shared on file descriptor
+        * or between different processes.).
+        */
+       args->op = (args->op & ~LINUX_FUTEX_PRIVATE_FLAG);
+
+       switch (args->op) {
+       case LINUX_FUTEX_WAIT:
+               LINUX_CTR2(sys_futex, "WAIT val %d uaddr %p",
+                   args->val, args->uaddr);
+#ifdef DEBUG
+               if (ldebug(sys_futex))
+                       kprintf(ARGS(sys_futex, "futex_wait val %d uaddr %p"),
+                           args->val, args->uaddr);
+#endif
+               error = futex_get(args->uaddr, &wp, &f, FUTEX_CREATE_WP);
+               if (error)
+                       return (error);
+               error = copyin(args->uaddr, &val, sizeof(val));
+               if (error) {
+                       LINUX_CTR1(sys_futex, "WAIT copyin failed %d",
+                           error);
+                       futex_put(f, wp);
+                       return (error);
+               }
+               if (val != args->val) {
+                       LINUX_CTR3(sys_futex, "WAIT uaddr %p val %d != uval %d",
+                           args->uaddr, args->val, val);
+                       futex_put(f, wp);
+                       return (EWOULDBLOCK);
+               }
+
+               error = futex_wait(f, wp, args->timeout);
+               break;
+
+       case LINUX_FUTEX_WAKE:
+
+               LINUX_CTR2(sys_futex, "WAKE val %d uaddr %p",
+                   args->val, args->uaddr);
+
+               /*
+                * XXX: Linux is able to cope with different addresses
+                * corresponding to the same mapped memory in the sleeping
+                * and waker process(es).
+                */
+#ifdef DEBUG
+               if (ldebug(sys_futex))
+                       kprintf(ARGS(sys_futex, "futex_wake val %d uaddr %p"),
+                           args->val, args->uaddr);
+#endif
+               error = futex_get(args->uaddr, NULL, &f, FUTEX_DONTCREATE);
+               if (error)
+                       return (error);
+               if (f == NULL) {
+                       args->sysmsg_iresult = 0;
+                       return (error);
+               }
+               args->sysmsg_iresult = futex_wake(f, args->val);
+               futex_put(f, NULL);
+               break;
+
+       case LINUX_FUTEX_CMP_REQUEUE:
+
+               LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p "
+                   "val %d val3 %d uaddr2 %p val2 %d",
+                   args->uaddr, args->val, args->val3, args->uaddr2,
+                   (int)(unsigned long)args->timeout);
+
+#ifdef DEBUG
+               if (ldebug(sys_futex))
+                       kprintf(ARGS(sys_futex, "futex_cmp_requeue uaddr %p "
+                           "val %d val3 %d uaddr2 %p val2 %d"),
+                           args->uaddr, args->val, args->val3, args->uaddr2,
+                           (int)(unsigned long)args->timeout);
+#endif
+               /*
+                * Linux allows this, we would not, it is an incorrect
+                * usage of declared ABI, so return EINVAL.
+                */
+               if (args->uaddr == args->uaddr2)
+                       return (EINVAL);
+               error = futex_get0(args->uaddr, &f, 0);
+               if (error)
+                       return (error);
+
+               /*
+                * To avoid deadlocks return EINVAL if second futex
+                * exists at this time. Otherwise create the new futex
+                * and ignore false positive LOR which thus happens.
+                *
+                * Glibc fall back to FUTEX_WAKE in case of any error
+                * returned by FUTEX_CMP_REQUEUE.
+                */
+               error = futex_get0(args->uaddr2, &f2, FUTEX_DONTEXISTS);
+               if (error) {
+                       futex_put(f, NULL);
+                       return (error);
+               }
+               error = copyin(args->uaddr, &val, sizeof(val));
+               if (error) {
+                       LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d",
+                           error);
+                       futex_put(f2, NULL);
+                       futex_put(f, NULL);
+                       return (error);
+               }
+               if (val != args->val3) {
+                       LINUX_CTR2(sys_futex, "CMP_REQUEUE val %d != uval %d",
+                           args->val, val);
+                       futex_put(f2, NULL);
+                       futex_put(f, NULL);
+                       return (EAGAIN);
+               }
+
+               nrwake = (int)(unsigned long)args->timeout;
+               args->sysmsg_iresult = futex_requeue(f, args->val, f2, nrwake);
+               futex_put(f2, NULL);
+               futex_put(f, NULL);
+               break;
+
+       case LINUX_FUTEX_WAKE_OP:
+
+               LINUX_CTR5(sys_futex, "WAKE_OP "
+                   "uaddr %p op %d val %x uaddr2 %p val3 %x",
+                   args->uaddr, args->op, args->val,
+                   args->uaddr2, args->val3);
+
+#ifdef DEBUG
+               if (ldebug(sys_futex))
+                       kprintf(ARGS(sys_futex, "futex_wake_op "
+                           "uaddr %p op %d val %x uaddr2 %p val3 %x"),
+                           args->uaddr, args->op, args->val,
+                           args->uaddr2, args->val3);
+#endif
+               error = futex_get0(args->uaddr, &f, 0);
+               if (error)
+                       return (error);
+               if (args->uaddr != args->uaddr2)
+                       error = futex_get0(args->uaddr2, &f2, 0);
+               if (error) {
+                       futex_put(f, NULL);
+                       return (error);
+               }
+
+               /*
+                * This function returns positive number as results and
+                * negative as errors
+                */
+               op_ret = futex_atomic_op(curproc, args->val3, args->uaddr2);
+
+               if (op_ret < 0) {
+                       /* XXX: We don't handle the EFAULT yet. */
+                       if (op_ret != -EFAULT) {
+                               if (f2 != NULL)
+                                       futex_put(f2, NULL);
+                               futex_put(f, NULL);
+                               return (-op_ret);
+                       }
+                       if (f2 != NULL)
+                               futex_put(f2, NULL);
+                       futex_put(f, NULL);
+                       return (EFAULT);
+               }
+
+               ret = futex_wake(f, args->val);
+
+               if (op_ret > 0) {
+                       op_ret = 0;
+                       nrwake = (int)(unsigned long)args->timeout;
+
+                       if (f2 != NULL)
+                               op_ret += futex_wake(f2, nrwake);
+                       else
+                               op_ret += futex_wake(f, nrwake);
+                       ret += op_ret;
+
+               }
+               if (f2 != NULL)
+                       futex_put(f2, NULL);
+               futex_put(f, NULL);
+               args->sysmsg_iresult = ret;
+               break;
+
+       case LINUX_FUTEX_LOCK_PI:
+               /* not yet implemented */
+               return (ENOSYS);
+
+       case LINUX_FUTEX_UNLOCK_PI:
+               /* not yet implemented */
+               return (ENOSYS);
+
+       case LINUX_FUTEX_TRYLOCK_PI:
+               /* not yet implemented */
+               return (ENOSYS);
+
+       case LINUX_FUTEX_REQUEUE:
+
+               /*
+                * Glibc does not use this operation since version 2.3.3,
+                * as it is racy and replaced by FUTEX_CMP_REQUEUE operation.
+                * Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when
+                * FUTEX_REQUEUE returned EINVAL.
+                */
+               return (EINVAL);
+
+       default:
+               kprintf("linux_sys_futex: unknown op %d\n", args->op);
+               return (ENOSYS);
+       }
+
+       return (error);
+}
+
+int
+sys_linux_set_robust_list(struct linux_set_robust_list_args *args)
+{
+#ifdef DEBUG
+       if (ldebug(set_robust_list))
+               kprintf(ARGS(set_robust_list, "head %p len %d"),
+                   args->head, args->len);
+#endif
+
+       if (args->len != sizeof(struct linux_robust_list_head))
+               return (EINVAL);
+
+       emuldata_set_robust(curproc, args->head);
+
+       return (0);
+}
+
+
+
+int
+sys_linux_get_robust_list(struct linux_get_robust_list_args *args)
+{
+       struct linux_emuldata *em;
+       struct linux_robust_list_head empty_head;
+       struct linux_robust_list_head *head;
+       l_size_t len = sizeof(struct linux_robust_list_head);
+       int error = 0;
+
+#ifdef DEBUG
+       if (ldebug(get_robust_list))
+               kprintf(ARGS(get_robust_list, ""));
+#endif
+       EMUL_LOCK();
+       if (args->pid == 0) {
+               em = emuldata_get(curproc);
+               KKASSERT(em != NULL);
+               if (em->robust_futexes == NULL) {
+                       bzero(&empty_head, sizeof(empty_head));
+                       head = &empty_head;
+               } else {
+                       head = em->robust_futexes;
+               }
+       } else {
+               struct proc *p;
+
+               p = pfind(args->pid);
+               if (p == NULL) {
+                       EMUL_UNLOCK();
+                       return (ESRCH);
+               }
+
+               em = emuldata_get(p);
+               /* XXX: ptrace? p_candebug?*/
+               if (priv_check(curthread, PRIV_CRED_SETUID) ||
+                   priv_check(curthread, PRIV_CRED_SETEUID)/* ||
+                   p_candebug(curproc, p) */) {
+                       EMUL_UNLOCK();
+                       return (EPERM);
+               }
+               head = em->robust_futexes;
+
+       }
+       EMUL_UNLOCK();
+
+       error = copyout(&len, args->len, sizeof(l_size_t));
+       if (error)
+               return (EFAULT);
+
+       error = copyout(head, args->head, sizeof(struct linux_robust_list_head));
+
+       return (error);
+}
+
+static int
+handle_futex_death(struct proc *p, uint32_t *uaddr, int pi)
+{
+       uint32_t uval, nval, mval;
+       struct futex *f;
+       int error;
+
+retry:
+       if (copyin(uaddr, &uval, 4))
+               return (EFAULT);
+       if ((uval & FUTEX_TID_MASK) == p->p_pid) {
+               mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
+               nval = casuword((ulong *)uaddr, uval, mval);
+
+               if (nval == -1)
+                       return (EFAULT);
+
+               if (nval != uval)
+                       goto retry;
+
+               if (!pi && (uval & FUTEX_WAITERS)) {
+                       error = futex_get(uaddr, NULL, &f,
+                           FUTEX_DONTCREATE);
+                       if (error)
+                               return (error);
+                       if (f != NULL) {
+                               futex_wake(f, 1);
+                               futex_put(f, NULL);
+                       }
+               }
+       }
+
+       return (0);
+}
+
+static int
+fetch_robust_entry(struct linux_robust_list **entry,
+    struct linux_robust_list **head, int *pi)
+{
+       l_ulong uentry;
+
+       if (copyin((const void *)head, &uentry, sizeof(l_ulong)))
+               return (EFAULT);
+
+       *entry = (void *)(uentry & ~1UL);
+       *pi = uentry & 1;
+
+       return (0);
+}
+
+/* This walks the list of robust futexes releasing them. */
+void
+release_futexes(struct proc *p)
+{
+       struct linux_robust_list_head *head = NULL;
+       struct linux_robust_list *entry, *next_entry, *pending;
+       unsigned int limit = 2048, pi, next_pi, pip;
+       struct linux_emuldata *em;
+       l_long futex_offset;
+       int rc;
+
+       EMUL_LOCK();
+       KKASSERT(p != NULL);
+       em = emuldata_get(p);
+       KKASSERT(em != NULL);
+       head = em->robust_futexes;
+       EMUL_UNLOCK();
+
+       if (head == NULL)
+               return;
+
+       if (fetch_robust_entry(&entry, PTRIN(&head->list.next), &pi))
+               return;
+
+       if (copyin(&head->futex_offset, &futex_offset, sizeof(futex_offset)))
+               return;
+
+       if (fetch_robust_entry(&pending, PTRIN(&head->pending_list), &pip))
+               return;
+
+       while (entry != &head->list) {
+               rc = fetch_robust_entry(&next_entry, PTRIN(&entry->next), &next_pi);
+
+               if (entry != pending)
+                       if (handle_futex_death(p, (uint32_t *)entry + futex_offset, pi))
+                               return;
+               if (rc)
+                       return;
+
+               entry = next_entry;
+               pi = next_pi;
+
+               if (!--limit)
+                       break;
+
+#if 0
+               /* XXX: not sure about this yield, was sched_relinquish(curthread); */
+               lwkt_deschedule(curthread);
+               lwkt_yield();
+#endif
+       }
+
+       if (pending)
+               handle_futex_death(p, (uint32_t *)pending + futex_offset, pip);
+}
diff --git a/sys/emulation/linux/linux_futex.h b/sys/emulation/linux/linux_futex.h
new file mode 100644 (file)
index 0000000..d9335eb
--- /dev/null
@@ -0,0 +1,87 @@
+/*     $NetBSD: linux_futex.h,v 1.3 2008/10/126 16:38:22 christos Exp $ */
+
+/*-
+ * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Emmanuel Dreyfus
+ * 4. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_FUTEX_H
+#define _LINUX_FUTEX_H
+
+extern LIST_HEAD(futex_list, futex) futex_list;
+extern struct lock futex_lock;
+
+#define LINUX_FUTEX_WAIT       0
+#define LINUX_FUTEX_WAKE       1
+#define LINUX_FUTEX_FD         2       /* unused */
+#define LINUX_FUTEX_REQUEUE    3
+#define LINUX_FUTEX_CMP_REQUEUE        4
+#define LINUX_FUTEX_WAKE_OP    5
+
+/* XXX: what are these? netbsd doesn't have them */
+#define LINUX_FUTEX_LOCK_PI    6
+#define LINUX_FUTEX_UNLOCK_PI  7
+#define LINUX_FUTEX_TRYLOCK_PI 8
+
+#define LINUX_FUTEX_PRIVATE_FLAG       128
+
+#define FUTEX_OP_SET            0      /* *(int *)UADDR2 = OPARG; */
+#define FUTEX_OP_ADD            1      /* *(int *)UADDR2 += OPARG; */
+#define FUTEX_OP_OR             2      /* *(int *)UADDR2 |= OPARG; */
+#define FUTEX_OP_ANDN           3      /* *(int *)UADDR2 &= ~OPARG; */
+#define FUTEX_OP_XOR            4      /* *(int *)UADDR2 ^= OPARG; */
+
+#define FUTEX_OP_OPARG_SHIFT    8      /* Use (1 << OPARG) instead of OPARG.  */
+
+#define FUTEX_OP_CMP_EQ         0      /* if (oldval == CMPARG) wake */
+#define FUTEX_OP_CMP_NE         1      /* if (oldval != CMPARG) wake */
+#define FUTEX_OP_CMP_LT         2      /* if (oldval < CMPARG) wake */
+#define FUTEX_OP_CMP_LE         3      /* if (oldval <= CMPARG) wake */
+#define FUTEX_OP_CMP_GT         4      /* if (oldval > CMPARG) wake */
+#define FUTEX_OP_CMP_GE         5      /* if (oldval >= CMPARG) wake */
+
+#define        FUTEX_WAITERS           0x80000000
+#define        FUTEX_OWNER_DIED        0x40000000
+#define        FUTEX_TID_MASK          0x3fffffff
+
+
+/* robust futexes */
+struct linux_robust_list {
+       struct linux_robust_list        *next;
+};
+
+struct linux_robust_list_head {
+       struct linux_robust_list        list;
+       l_long                          futex_offset;
+       struct linux_robust_list        *pending_list;
+};
+
+void   release_futexes(struct proc *);
+extern struct lock futex_mtx;
+#endif /* !_LINUX_FUTEX_H */
index 39f058c..4515aa1 100644 (file)
@@ -568,6 +568,20 @@ linux_ioctl_TCSETAF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, stru
        return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred, NULL));
 }
 
+static int
+linux_ioctl_TIOCLINUX(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
+{
+       switch ((u_char)*data) {
+       case 11: /* LINUX_TIOCLINUX_KERNMSG */
+               return 0;
+       default:
+               kprintf("Unknown LINUX_TIOCLINUX: %d\n", ((u_char)*data));
+               kprintf("cmd = %lu, ocmd = %lu\n", cmd, ocmd);
+               return 0;
+       }
+       return 0;
+}
+
 static int
 linux_ioctl_TCXONC(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
 {
@@ -1048,6 +1062,7 @@ linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
        char ifname[IFNAMSIZ];
        l_short flags;
 
+#if 0
        if (fp->f_type != DTYPE_SOCKET) {
                /* XXX: I doubt this is correct because
                 *      we don't translate the ifname and
@@ -1055,8 +1070,12 @@ linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
                 */
                return (fo_ioctl(fp, SIOCGIFFLAGS, data, cred, NULL));
        }
+#endif
 
        ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
+       if (ifp == NULL)
+               return (EINVAL);
+
        flags = ifp->if_flags;
        /* these flags have no Linux equivalent */
        flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
@@ -1074,6 +1093,43 @@ linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
 #define ARPHRD_ETHER   1
 #define ARPHRD_LOOPBACK        772
 
+/* XXX: could implement using native ioctl, so only mapping */
+static int
+linux_ioctl_SIOCGIFINDEX(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
+{
+       struct l_ifreq *ifr = (struct l_ifreq *)data;
+       struct ifnet *ifp;
+       char ifname[IFNAMSIZ];
+       l_int index;
+
+       ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
+       if (ifp == NULL)
+               return EINVAL;
+
+#if DEBUG
+       kprintf("Interface index: %d\n", ifp->if_index);
+#endif
+
+       index = ifp->if_index;
+       return (copyout(&index, &ifr->ifr_ifindex, sizeof(index)));
+}
+
+static int
+linux_ioctl_SIOCGIFMETRIC(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
+{
+       struct l_ifreq *ifr = (struct l_ifreq *)data;
+       struct ifnet *ifp;
+       char ifname[IFNAMSIZ];
+       l_int metric;
+
+       ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
+       if (ifp == NULL)
+               return EINVAL;
+
+       metric = ifp->if_metric;
+       return (copyout(&metric, &ifr->ifr_ifmetric, sizeof(metric)));
+}
+
 static int
 linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
 {
@@ -1085,6 +1141,10 @@ linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
        struct ifaddr_container *ifac;
 
        ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
+       if (ifp == NULL) {
+               return EINVAL;
+       }
+
        if (ifp->if_type == IFT_LOOP) {
                bzero(&ifr->ifr_hwaddr, sizeof lsa);
                ifr->ifr_hwaddr.sa_family = ARPHRD_LOOPBACK;
@@ -1186,6 +1246,7 @@ static struct ioctl_map_range linux_ioctl_map_entries[] = {
        MAPPED_