Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile
new file mode 100644
index 0000000..8c86630
--- /dev/null
+++ b/arch/sparc64/solaris/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the Solaris binary emulation.
+#
+
+EXTRA_AFLAGS := -ansi
+
+solaris-objs := entry64.o fs.o misc.o signal.o systbl.o socket.o \
+		ioctl.o ipc.o socksys.o timod.o
+
+obj-$(CONFIG_SOLARIS_EMUL) += solaris.o
diff --git a/arch/sparc64/solaris/conv.h b/arch/sparc64/solaris/conv.h
new file mode 100644
index 0000000..5faf59a
--- /dev/null
+++ b/arch/sparc64/solaris/conv.h
@@ -0,0 +1,38 @@
+/* $Id: conv.h,v 1.4 1998/08/15 20:42:51 davem Exp $
+ * conv.h: Utility macros for Solaris emulation
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+ 
+/* #define DEBUG_SOLARIS */
+#define DEBUG_SOLARIS_KMALLOC
+
+#ifndef __ASSEMBLY__
+
+#include <asm/unistd.h>
+
+/* Use this to get at 32-bit user passed pointers. */
+#define A(__x)				\
+({	unsigned long __ret;		\
+	__asm__ ("srl	%0, 0, %0"	\
+		 : "=r" (__ret)		\
+		 : "0" (__x));		\
+	(void __user *)__ret;		\
+})
+
+extern unsigned sys_call_table[];
+extern unsigned sys_call_table32[];
+extern unsigned sunos_sys_table[];
+
+#define SYS(name) ((long)sys_call_table[__NR_##name])
+#define SUNOS(x) ((long)sunos_sys_table[x])
+
+#ifdef DEBUG_SOLARIS
+#define SOLD(s) printk("%s,%d,%s(): %s\n",__FILE__,__LINE__,__FUNCTION__,(s))
+#define SOLDD(s) printk("solaris: "); printk s
+#else
+#define SOLD(s)
+#define SOLDD(s)
+#endif
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S
new file mode 100644
index 0000000..0cc9dad
--- /dev/null
+++ b/arch/sparc64/solaris/entry64.S
@@ -0,0 +1,218 @@
+/* $Id: entry64.S,v 1.7 2002/02/09 19:49:31 davem Exp $
+ * entry64.S:  Solaris syscall emulation entry point.
+ *
+ * Copyright (C) 1996,1997,1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Miguel de Icaza      (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/errno.h>
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+
+#include "conv.h"
+
+#define NR_SYSCALLS	256
+
+	.text
+solaris_syscall_trace:
+	call		syscall_trace
+	 nop
+	srl		%i0, 0, %o0
+	mov		%i4, %o4
+	srl		%i1, 0, %o1
+	mov		%i5, %o5
+	andcc		%l3, 1, %g0
+	be,pt		%icc, 2f
+	 srl		%i2, 0, %o2
+	b,pt		%xcc, 2f
+	 add		%sp, PTREGS_OFF, %o0
+
+solaris_sucks:
+/* Solaris is a big system which needs to be able to do all the things
+ * in Inf+1 different ways */
+	add		%i6, 0x5c, %o0
+	mov		%i0, %g1
+	mov		%i1, %i0
+	mov		%i2, %i1
+	srl		%o0, 0, %o0
+	mov		%i3, %i2
+	movrz		%g1, 256, %g1 /* Ensure we don't loop forever */
+	mov		%i4, %i3
+	mov		%i5, %i4
+	ba,pt		%xcc, solaris_sparc_syscall
+exen:	 lduwa		[%o0] ASI_S, %i5
+
+exenf:	ba,pt		%xcc, solaris_sparc_syscall
+	 clr		%i5
+
+/* For shared binaries, binfmt_elf32 already sets up personality
+   and exec_domain. This is to handle static binaries as well */
+solaris_reg:
+	call		solaris_register
+	 nop
+	ba,pt		%xcc, 1f
+	 mov		%i4, %o4
+
+linux_syscall_for_solaris:
+	sethi		%hi(sys_call_table32), %l6
+	or		%l6, %lo(sys_call_table32), %l6
+	sll		%l3, 2, %l4
+	ba,pt		%xcc, 10f
+	 lduw		[%l6 + %l4], %l3
+
+	/* Solaris system calls enter here... */
+	.align	32
+	.globl	solaris_sparc_syscall, entry64_personality_patch
+solaris_sparc_syscall:
+entry64_personality_patch:
+	ldub		[%g4 + 0x0], %l0
+	cmp		%g1, 255
+	bg,pn		%icc, solaris_unimplemented
+	 srl		%g1, 0, %g1
+	sethi		%hi(solaris_sys_table), %l7
+	or		%l7, %lo(solaris_sys_table), %l7
+	brz,pn		%g1, solaris_sucks
+	 mov		%i4, %o4
+	sll		%g1, 2, %l4
+	cmp		%l0, 1
+	bne,pn		%icc, solaris_reg
+1:	 srl		%i0, 0, %o0
+	lduw		[%l7 + %l4], %l3
+	srl		%i1, 0, %o1
+	ldx		[%g6 + TI_FLAGS], %l5
+	cmp		%l3, NR_SYSCALLS
+	bleu,a,pn	%xcc, linux_syscall_for_solaris
+	 nop
+	andcc		%l3, 1, %g0
+	bne,a,pn	%icc, 10f
+	 add		%sp, PTREGS_OFF, %o0
+10:	srl		%i2, 0, %o2
+	mov		%i5, %o5
+	andn		%l3, 3, %l7
+	andcc		%l5, _TIF_SYSCALL_TRACE, %g0				
+	bne,pn		%icc, solaris_syscall_trace		
+	 mov		%i0, %l5
+2:	call		%l7
+	 srl		%i3, 0, %o3
+ret_from_solaris:
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
+	ldx		[%g6 + TI_FLAGS], %l6
+	sra		%o0, 0, %o0
+	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+	ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
+	cmp		%o0, -ERESTART_RESTARTBLOCK
+	sllx		%g2, 32, %g2
+	bgeu,pn		%xcc, 1f
+	 andcc		%l6, _TIF_SYSCALL_TRACE, %l6	
+
+	/* System call success, clear Carry condition code. */
+	andn		%g3, %g2, %g3
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]	
+	bne,pn		%icc, solaris_syscall_trace2
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1
+	andcc		%l1, 1, %g0
+	bne,pn		%icc, 2f
+	 clr		%l6
+	add		%l1, 0x4, %l2				         
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]	 ! pc = npc
+	call		rtrap
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4
+
+	/* When tnpc & 1, this comes from setcontext and we don't want to advance pc */
+2:	andn		%l1, 3, %l1
+	call		rtrap
+	 stx		%l1, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc&~3
+
+1:
+	/* System call failure, set Carry condition code.
+	 * Also, get abs(errno) to return to the process.
+	 */
+	sub		%g0, %o0, %o0
+	or		%g3, %g2, %g3
+	cmp		%o0, ERANGE	/* 0-ERANGE are identity mapped */
+	bleu,pt		%icc, 1f
+	 cmp		%o0, EMEDIUMTYPE
+	bgu,pn		%icc, 1f
+	 sethi		%hi(solaris_err_table), %l6
+	sll		%o0, 2, %o0
+	or		%l6, %lo(solaris_err_table), %l6
+	ldsw		[%l6 + %o0], %o0
+1:	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
+	mov		1, %l6
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
+	bne,pn		%icc, solaris_syscall_trace2
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1
+	andcc		%l1, 1, %g0
+	bne,pn		%icc, 2b
+	 add		%l1, 0x4, %l2
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]  ! pc = npc
+	call		rtrap
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4 
+
+solaris_syscall_trace2:
+	call		syscall_trace
+	 add		%l1, 0x4, %l2			/* npc = npc+4 */
+	andcc		%l1, 1, %g0
+	bne,pn		%icc, 2b
+	 nop
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
+	call		rtrap
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
+
+	/* This one is tricky, so that's why we do it in assembly */
+	.globl		solaris_sigsuspend
+solaris_sigsuspend:
+	call		do_sol_sigsuspend
+	 nop
+	brlz,pn		%o0, ret_from_solaris
+	 nop
+	call		sys_sigsuspend
+	 stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
+
+	.globl		solaris_getpid
+solaris_getpid:
+	call		sys_getppid
+	 nop
+	call		sys_getpid
+	 stx		%o0, [%sp + PTREGS_OFF + PT_V9_I1]
+	b,pt		%xcc, ret_from_solaris
+	 nop
+
+	.globl	solaris_getuid
+solaris_getuid:
+	call		sys_geteuid
+	 nop
+	call		sys_getuid
+	 stx		%o1, [%sp + PTREGS_OFF + PT_V9_I1]
+	b,pt		%xcc, ret_from_solaris
+	 nop
+
+	.globl	solaris_getgid
+solaris_getgid:
+	call		sys_getegid
+	 nop
+	call		sys_getgid
+	 stx		%o1, [%sp + PTREGS_OFF + PT_V9_I1]
+	b,pt		%xcc, ret_from_solaris
+	 nop
+
+	.globl		solaris_unimplemented
+solaris_unimplemented:
+	call		do_sol_unimplemented
+	 add		%sp, PTREGS_OFF, %o0
+	ba,pt		%xcc, ret_from_solaris
+	 nop
+
+	.section	__ex_table,#alloc
+	.align		4
+	.word		exen, exenf
+
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
new file mode 100644
index 0000000..d7c99fa
--- /dev/null
+++ b/arch/sparc64/solaris/fs.c
@@ -0,0 +1,739 @@
+/* $Id: fs.c,v 1.27 2002/02/08 03:57:14 davem Exp $
+ * fs.c: fs related syscall emulation for Solaris
+ *
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * 1999-08-19 Implemented solaris F_FREESP (truncate)
+ *            fcntl, by Jason Rappleye (rappleye@ccr.buffalo.edu)
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/stat.h>
+#include <linux/smp_lock.h>
+#include <linux/limits.h>
+#include <linux/resource.h>
+#include <linux/quotaops.h>
+#include <linux/mount.h>
+#include <linux/vfs.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/ptrace.h>
+
+#include "conv.h"
+
+#define R3_VERSION	1
+#define R4_VERSION	2
+
+typedef struct {
+	s32	tv_sec;
+	s32	tv_nsec;
+} timestruct_t;
+
+struct sol_stat {
+	u32		st_dev;
+	s32		st_pad1[3];     /* network id */
+	u32		st_ino;
+	u32		st_mode;
+	u32		st_nlink;
+	u32		st_uid;
+	u32		st_gid;
+	u32		st_rdev;
+	s32		st_pad2[2];
+	s32		st_size;
+	s32		st_pad3;	/* st_size, off_t expansion */
+	timestruct_t	st_atime;
+	timestruct_t	st_mtime;
+	timestruct_t	st_ctime;
+	s32		st_blksize;
+	s32		st_blocks;
+	char		st_fstype[16];
+	s32		st_pad4[8];     /* expansion area */
+};
+
+struct sol_stat64 {
+	u32		st_dev;
+	s32		st_pad1[3];     /* network id */
+	u64		st_ino;
+	u32		st_mode;
+	u32		st_nlink;
+	u32		st_uid;
+	u32		st_gid;
+	u32		st_rdev;
+	s32		st_pad2[2];
+	s64		st_size;
+	timestruct_t	st_atime;
+	timestruct_t	st_mtime;
+	timestruct_t	st_ctime;
+	s64		st_blksize;
+	s32		st_blocks;
+	char		st_fstype[16];
+	s32		st_pad4[4];     /* expansion area */
+};
+
+#define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8))
+
+static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf)
+{
+	if (kbuf->size > MAX_NON_LFS ||
+	    !sysv_valid_dev(kbuf->dev) ||
+	    !sysv_valid_dev(kbuf->rdev))
+		return -EOVERFLOW;
+	if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev)	||
+	    __put_user (kbuf->ino, &ubuf->st_ino)		||
+	    __put_user (kbuf->mode, &ubuf->st_mode)		||
+	    __put_user (kbuf->nlink, &ubuf->st_nlink)	||
+	    __put_user (kbuf->uid, &ubuf->st_uid)		||
+	    __put_user (kbuf->gid, &ubuf->st_gid)		||
+	    __put_user (sysv_encode_dev(kbuf->rdev), &ubuf->st_rdev)	||
+	    __put_user (kbuf->size, &ubuf->st_size)		||
+	    __put_user (kbuf->atime.tv_sec, &ubuf->st_atime.tv_sec)	||
+	    __put_user (kbuf->atime.tv_nsec, &ubuf->st_atime.tv_nsec)	||
+	    __put_user (kbuf->mtime.tv_sec, &ubuf->st_mtime.tv_sec)	||
+	    __put_user (kbuf->mtime.tv_nsec, &ubuf->st_mtime.tv_nsec)	||
+	    __put_user (kbuf->ctime.tv_sec, &ubuf->st_ctime.tv_sec)	||
+	    __put_user (kbuf->ctime.tv_nsec, &ubuf->st_ctime.tv_nsec)	||
+	    __put_user (kbuf->blksize, &ubuf->st_blksize)	||
+	    __put_user (kbuf->blocks, &ubuf->st_blocks)	||
+	    __put_user (UFSMAGIC, (unsigned __user *)ubuf->st_fstype))
+		return -EFAULT;
+	return 0;
+}
+
+static inline int putstat64(struct sol_stat64 __user *ubuf, struct kstat *kbuf)
+{
+	if (!sysv_valid_dev(kbuf->dev) || !sysv_valid_dev(kbuf->rdev))
+		return -EOVERFLOW;
+	if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev)	||
+	    __put_user (kbuf->ino, &ubuf->st_ino)		||
+	    __put_user (kbuf->mode, &ubuf->st_mode)		||
+	    __put_user (kbuf->nlink, &ubuf->st_nlink)	||
+	    __put_user (kbuf->uid, &ubuf->st_uid)		||
+	    __put_user (kbuf->gid, &ubuf->st_gid)		||
+	    __put_user (sysv_encode_dev(kbuf->rdev), &ubuf->st_rdev)	||
+	    __put_user (kbuf->size, &ubuf->st_size)		||
+	    __put_user (kbuf->atime.tv_sec, &ubuf->st_atime.tv_sec)	||
+	    __put_user (kbuf->atime.tv_nsec, &ubuf->st_atime.tv_nsec)	||
+	    __put_user (kbuf->mtime.tv_sec, &ubuf->st_mtime.tv_sec)	||
+	    __put_user (kbuf->mtime.tv_nsec, &ubuf->st_mtime.tv_nsec)	||
+	    __put_user (kbuf->ctime.tv_sec, &ubuf->st_ctime.tv_sec)	||
+	    __put_user (kbuf->ctime.tv_nsec, &ubuf->st_ctime.tv_nsec)	||
+	    __put_user (kbuf->blksize, &ubuf->st_blksize)	||
+	    __put_user (kbuf->blocks, &ubuf->st_blocks)	||
+	    __put_user (UFSMAGIC, (unsigned __user *)ubuf->st_fstype))
+		return -EFAULT;
+	return 0;
+}
+
+asmlinkage int solaris_stat(u32 filename, u32 statbuf)
+{
+	struct kstat s;
+	int ret = vfs_stat(A(filename), &s);
+	if (!ret)
+		return putstat(A(statbuf), &s);
+	return ret;
+}
+
+asmlinkage int solaris_xstat(int vers, u32 filename, u32 statbuf)
+{
+	/* Solaris doesn't bother with looking at vers, so we do neither */
+	return solaris_stat(filename, statbuf);
+}
+
+asmlinkage int solaris_stat64(u32 filename, u32 statbuf)
+{
+	struct kstat s;
+	int ret = vfs_stat(A(filename), &s);
+	if (!ret)
+		return putstat64(A(statbuf), &s);
+	return ret;
+}
+
+asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
+{
+	struct kstat s;
+	int ret = vfs_lstat(A(filename), &s);
+	if (!ret)
+		return putstat(A(statbuf), &s);
+	return ret;
+}
+
+asmlinkage int solaris_lxstat(int vers, u32 filename, u32 statbuf)
+{
+	return solaris_lstat(filename, statbuf);
+}
+
+asmlinkage int solaris_lstat64(u32 filename, u32 statbuf)
+{
+	struct kstat s;
+	int ret = vfs_lstat(A(filename), &s);
+	if (!ret)
+		return putstat64(A(statbuf), &s);
+	return ret;
+}
+
+asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf)
+{
+	struct kstat s;
+	int ret = vfs_fstat(fd, &s);
+	if (!ret)
+		return putstat(A(statbuf), &s);
+	return ret;
+}
+
+asmlinkage int solaris_fxstat(int vers, u32 fd, u32 statbuf)
+{
+	return solaris_fstat(fd, statbuf);
+}
+
+asmlinkage int solaris_fstat64(unsigned int fd, u32 statbuf)
+{
+	struct kstat s;
+	int ret = vfs_fstat(fd, &s);
+	if (!ret)
+		return putstat64(A(statbuf), &s);
+	return ret;
+}
+
+asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev)
+{
+	int (*sys_mknod)(const char __user *,int,unsigned) = 
+		(int (*)(const char __user *,int,unsigned))SYS(mknod);
+	int major = sysv_major(dev);
+	int minor = sysv_minor(dev);
+
+	/* minor is guaranteed to be OK for MKDEV, major might be not */
+	if (major > 0xfff)
+		return -EINVAL;
+	return sys_mknod(A(path), mode, new_encode_dev(MKDEV(major,minor)));
+}
+
+asmlinkage int solaris_xmknod(int vers, u32 path, u32 mode, s32 dev)
+{
+	return solaris_mknod(path, mode, dev);
+}
+
+asmlinkage int solaris_getdents64(unsigned int fd, void __user *dirent, unsigned int count)
+{
+	int (*sys_getdents)(unsigned int, void __user *, unsigned int) =
+		(int (*)(unsigned int, void __user *, unsigned int))SYS(getdents);
+		
+	return sys_getdents(fd, dirent, count);
+}
+
+/* This statfs thingie probably will go in the near future, but... */
+
+struct sol_statfs {
+	short	f_type;
+	s32	f_bsize;
+	s32	f_frsize;
+	s32	f_blocks;
+	s32	f_bfree;
+	u32	f_files;
+	u32	f_ffree;
+	char	f_fname[6];
+	char	f_fpack[6];
+};
+
+asmlinkage int solaris_statfs(u32 path, u32 buf, int len, int fstype)
+{
+	int ret;
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	int (*sys_statfs)(const char __user *,struct statfs __user *) = 
+		(int (*)(const char __user *,struct statfs __user *))SYS(statfs);
+	struct sol_statfs __user *ss = A(buf);
+	
+	if (len != sizeof(struct sol_statfs)) return -EINVAL;
+	if (!fstype) {
+		/* FIXME: mixing userland and kernel pointers */
+		set_fs (KERNEL_DS);
+		ret = sys_statfs(A(path), &s);
+		set_fs (old_fs);
+		if (!ret) {
+			if (put_user (s.f_type, &ss->f_type)		||
+			    __put_user (s.f_bsize, &ss->f_bsize)	||
+			    __put_user (0, &ss->f_frsize)		||
+			    __put_user (s.f_blocks, &ss->f_blocks)	||
+			    __put_user (s.f_bfree, &ss->f_bfree)	||
+			    __put_user (s.f_files, &ss->f_files)	||
+			    __put_user (s.f_ffree, &ss->f_ffree)	||
+			    __clear_user (&ss->f_fname, 12))
+				return -EFAULT;
+		}
+		return ret;
+	}
+/* Linux can't stat unmounted filesystems so we
+ * simply lie and claim 100MB of 1GB is free. Sorry.
+ */
+	if (put_user (fstype, &ss->f_type)		||
+	    __put_user (1024, &ss->f_bsize)		||
+	    __put_user (0, &ss->f_frsize)		||
+	    __put_user (1024*1024, &ss->f_blocks)	||
+	    __put_user (100*1024, &ss->f_bfree)		||
+	    __put_user (60000, &ss->f_files)		||
+	    __put_user (50000, &ss->f_ffree)		||
+	    __clear_user (&ss->f_fname, 12))
+		return -EFAULT;
+	return 0;
+}
+
+asmlinkage int solaris_fstatfs(u32 fd, u32 buf, int len, int fstype)
+{
+	int ret;
+	struct statfs s;
+	mm_segment_t old_fs = get_fs();
+	int (*sys_fstatfs)(unsigned,struct statfs __user *) = 
+		(int (*)(unsigned,struct statfs __user *))SYS(fstatfs);
+	struct sol_statfs __user *ss = A(buf);
+	
+	if (len != sizeof(struct sol_statfs)) return -EINVAL;
+	if (!fstype) {
+		set_fs (KERNEL_DS);
+		ret = sys_fstatfs(fd, &s);
+		set_fs (old_fs);
+		if (!ret) {
+			if (put_user (s.f_type, &ss->f_type)		||
+			    __put_user (s.f_bsize, &ss->f_bsize)	||
+			    __put_user (0, &ss->f_frsize)		||
+			    __put_user (s.f_blocks, &ss->f_blocks)	||
+			    __put_user (s.f_bfree, &ss->f_bfree)	||
+			    __put_user (s.f_files, &ss->f_files)	||
+			    __put_user (s.f_ffree, &ss->f_ffree)	||
+			    __clear_user (&ss->f_fname, 12))
+				return -EFAULT;
+		}
+		return ret;
+	}
+	/* Otherwise fstatfs is the same as statfs */
+	return solaris_statfs(0, buf, len, fstype);
+}
+
+struct sol_statvfs {
+	u32	f_bsize;
+	u32	f_frsize;
+	u32	f_blocks;
+	u32	f_bfree;
+	u32	f_bavail;
+	u32	f_files;
+	u32	f_ffree;
+	u32	f_favail;
+	u32	f_fsid;
+	char	f_basetype[16];
+	u32	f_flag;
+	u32	f_namemax;
+	char	f_fstr[32];
+	u32	f_filler[16];
+};
+
+struct sol_statvfs64 {
+	u32	f_bsize;
+	u32	f_frsize;
+	u64	f_blocks;
+	u64	f_bfree;
+	u64	f_bavail;
+	u64	f_files;
+	u64	f_ffree;
+	u64	f_favail;
+	u32	f_fsid;
+	char	f_basetype[16];
+	u32	f_flag;
+	u32	f_namemax;
+	char	f_fstr[32];
+	u32	f_filler[16];
+};
+
+static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf)
+{
+	struct kstatfs s;
+	int error;
+	struct sol_statvfs __user *ss = A(buf);
+
+	error = vfs_statfs(mnt->mnt_sb, &s);
+	if (!error) {
+		const char *p = mnt->mnt_sb->s_type->name;
+		int i = 0;
+		int j = strlen (p);
+		
+		if (j > 15) j = 15;
+		if (IS_RDONLY(inode)) i = 1;
+		if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
+		if (!sysv_valid_dev(inode->i_sb->s_dev))
+			return -EOVERFLOW;
+		if (put_user (s.f_bsize, &ss->f_bsize)		||
+		    __put_user (0, &ss->f_frsize)		||
+		    __put_user (s.f_blocks, &ss->f_blocks)	||
+		    __put_user (s.f_bfree, &ss->f_bfree)	||
+		    __put_user (s.f_bavail, &ss->f_bavail)	||
+		    __put_user (s.f_files, &ss->f_files)	||
+		    __put_user (s.f_ffree, &ss->f_ffree)	||
+		    __put_user (s.f_ffree, &ss->f_favail)	||
+		    __put_user (sysv_encode_dev(inode->i_sb->s_dev), &ss->f_fsid) ||
+		    __copy_to_user (ss->f_basetype,p,j)		||
+		    __put_user (0, (char __user *)&ss->f_basetype[j])	||
+		    __put_user (s.f_namelen, &ss->f_namemax)	||
+		    __put_user (i, &ss->f_flag)			||		    
+		    __clear_user (&ss->f_fstr, 32))
+			return -EFAULT;
+	}
+	return error;
+}
+
+static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf)
+{
+	struct kstatfs s;
+	int error;
+	struct sol_statvfs64 __user *ss = A(buf);
+			
+	error = vfs_statfs(mnt->mnt_sb, &s);
+	if (!error) {
+		const char *p = mnt->mnt_sb->s_type->name;
+		int i = 0;
+		int j = strlen (p);
+		
+		if (j > 15) j = 15;
+		if (IS_RDONLY(inode)) i = 1;
+		if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
+		if (!sysv_valid_dev(inode->i_sb->s_dev))
+			return -EOVERFLOW;
+		if (put_user (s.f_bsize, &ss->f_bsize)		||
+		    __put_user (0, &ss->f_frsize)		||
+		    __put_user (s.f_blocks, &ss->f_blocks)	||
+		    __put_user (s.f_bfree, &ss->f_bfree)	||
+		    __put_user (s.f_bavail, &ss->f_bavail)	||
+		    __put_user (s.f_files, &ss->f_files)	||
+		    __put_user (s.f_ffree, &ss->f_ffree)	||
+		    __put_user (s.f_ffree, &ss->f_favail)	||
+		    __put_user (sysv_encode_dev(inode->i_sb->s_dev), &ss->f_fsid) ||
+		    __copy_to_user (ss->f_basetype,p,j)		||
+		    __put_user (0, (char __user *)&ss->f_basetype[j])	||
+		    __put_user (s.f_namelen, &ss->f_namemax)	||
+		    __put_user (i, &ss->f_flag)			||		    
+		    __clear_user (&ss->f_fstr, 32))
+			return -EFAULT;
+	}
+	return error;
+}
+
+asmlinkage int solaris_statvfs(u32 path, u32 buf)
+{
+	struct nameidata nd;
+	int error;
+
+	error = user_path_walk(A(path),&nd);
+	if (!error) {
+		struct inode * inode = nd.dentry->d_inode;
+		error = report_statvfs(nd.mnt, inode, buf);
+		path_release(&nd);
+	}
+	return error;
+}
+
+asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
+{
+	struct file * file;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (file) {
+		error = report_statvfs(file->f_vfsmnt, file->f_dentry->d_inode, buf);
+		fput(file);
+	}
+
+	return error;
+}
+
+asmlinkage int solaris_statvfs64(u32 path, u32 buf)
+{
+	struct nameidata nd;
+	int error;
+
+	lock_kernel();
+	error = user_path_walk(A(path), &nd);
+	if (!error) {
+		struct inode * inode = nd.dentry->d_inode;
+		error = report_statvfs64(nd.mnt, inode, buf);
+		path_release(&nd);
+	}
+	unlock_kernel();
+	return error;
+}
+
+asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
+{
+	struct file * file;
+	int error;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (file) {
+		lock_kernel();
+		error = report_statvfs64(file->f_vfsmnt, file->f_dentry->d_inode, buf);
+		unlock_kernel();
+		fput(file);
+	}
+	return error;
+}
+
+extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
+
+asmlinkage int solaris_open(u32 fname, int flags, u32 mode)
+{
+	const char *filename = (const char *)(long)fname;
+	int fl = flags & 0xf;
+
+	/* Translate flags first. */
+	if (flags & 0x2000) fl |= O_LARGEFILE;
+	if (flags & 0x8050) fl |= O_SYNC;
+	if (flags & 0x80) fl |= O_NONBLOCK;
+	if (flags & 0x100) fl |= O_CREAT;
+	if (flags & 0x200) fl |= O_TRUNC;
+	if (flags & 0x400) fl |= O_EXCL;
+	if (flags & 0x800) fl |= O_NOCTTY;
+	flags = fl;
+
+	return sparc32_open(filename, flags, mode);
+}
+
+#define SOL_F_SETLK	6
+#define SOL_F_SETLKW	7
+#define SOL_F_FREESP    11
+#define SOL_F_ISSTREAM  13
+#define SOL_F_GETLK     14
+#define SOL_F_PRIV      15
+#define SOL_F_NPRIV     16
+#define SOL_F_QUOTACTL  17
+#define SOL_F_BLOCKS    18
+#define SOL_F_BLKSIZE   19
+#define SOL_F_GETOWN    23
+#define SOL_F_SETOWN    24
+
+struct sol_flock {
+	short	l_type;
+	short	l_whence;
+	u32	l_start;
+	u32	l_len;
+	s32	l_sysid;
+	s32	l_pid;
+	s32	l_pad[4];
+};
+
+asmlinkage int solaris_fcntl(unsigned fd, unsigned cmd, u32 arg)
+{
+	int (*sys_fcntl)(unsigned,unsigned,unsigned long) = 
+		(int (*)(unsigned,unsigned,unsigned long))SYS(fcntl);
+	int ret, flags;
+
+	switch (cmd) {
+	case F_DUPFD:
+	case F_GETFD:
+	case F_SETFD: return sys_fcntl(fd, cmd, (unsigned long)arg);
+	case F_GETFL:
+		flags = sys_fcntl(fd, cmd, 0);
+		ret = flags & 0xf;
+		if (flags & O_SYNC) ret |= 0x8050;
+		if (flags & O_NONBLOCK) ret |= 0x80;
+		return ret;
+	case F_SETFL:
+		flags = arg & 0xf;
+		if (arg & 0x8050) flags |= O_SYNC;
+		if (arg & 0x80) flags |= O_NONBLOCK;
+		return sys_fcntl(fd, cmd, (long)flags);
+	case SOL_F_GETLK:
+	case SOL_F_SETLK:
+	case SOL_F_SETLKW:
+		{
+			struct flock f;
+			struct sol_flock __user *p = A(arg);
+			mm_segment_t old_fs = get_fs();
+
+			switch (cmd) {
+			case SOL_F_GETLK: cmd = F_GETLK; break;
+			case SOL_F_SETLK: cmd = F_SETLK; break;
+			case SOL_F_SETLKW: cmd = F_SETLKW; break;
+			}
+
+			if (get_user (f.l_type, &p->l_type) ||
+			    __get_user (f.l_whence, &p->l_whence) ||
+			    __get_user (f.l_start, &p->l_start) ||
+			    __get_user (f.l_len, &p->l_len) ||
+			    __get_user (f.l_pid, &p->l_sysid))
+				return -EFAULT;
+
+			set_fs(KERNEL_DS);
+			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+			set_fs(old_fs);
+
+			if (__put_user (f.l_type, &p->l_type) ||
+			    __put_user (f.l_whence, &p->l_whence) ||
+			    __put_user (f.l_start, &p->l_start) ||
+			    __put_user (f.l_len, &p->l_len) ||
+			    __put_user (f.l_pid, &p->l_pid) ||
+			    __put_user (0, &p->l_sysid))
+				return -EFAULT;
+
+			return ret;
+		}
+	case SOL_F_FREESP:
+	        { 
+		    int length;
+		    int (*sys_newftruncate)(unsigned int, unsigned long)=
+			    (int (*)(unsigned int, unsigned long))SYS(ftruncate);
+
+		    if (get_user(length, &((struct sol_flock __user *)A(arg))->l_start))
+			    return -EFAULT;
+
+		    return sys_newftruncate(fd, length);
+		}
+	};
+	return -EINVAL;
+}
+
+asmlinkage int solaris_ulimit(int cmd, int val)
+{
+	switch (cmd) {
+	case 1: /* UL_GETFSIZE - in 512B chunks */
+		return current->signal->rlim[RLIMIT_FSIZE].rlim_cur >> 9;
+	case 2: /* UL_SETFSIZE */
+		if ((unsigned long)val > (LONG_MAX>>9)) return -ERANGE;
+		val <<= 9;
+		task_lock(current->group_leader);
+		if (val > current->signal->rlim[RLIMIT_FSIZE].rlim_max) {
+			if (!capable(CAP_SYS_RESOURCE)) {
+				task_unlock(current->group_leader);
+				return -EPERM;
+			}
+			current->signal->rlim[RLIMIT_FSIZE].rlim_max = val;
+		}
+		current->signal->rlim[RLIMIT_FSIZE].rlim_cur = val;
+		task_unlock(current->group_leader);
+		return 0;
+	case 3: /* UL_GMEMLIM */
+		return current->signal->rlim[RLIMIT_DATA].rlim_cur;
+	case 4: /* UL_GDESLIM */
+		return NR_OPEN;
+	}
+	return -EINVAL;
+}
+
+/* At least at the time I'm writing this, Linux doesn't have ACLs, so we
+   just fake this */
+asmlinkage int solaris_acl(u32 filename, int cmd, int nentries, u32 aclbufp)
+{
+	return -ENOSYS;
+}
+
+asmlinkage int solaris_facl(unsigned int fd, int cmd, int nentries, u32 aclbufp)
+{
+	return -ENOSYS;
+}
+
+asmlinkage int solaris_pread(unsigned int fd, char __user *buf, u32 count, u32 pos)
+{
+	ssize_t (*sys_pread64)(unsigned int, char __user *, size_t, loff_t) =
+		(ssize_t (*)(unsigned int, char __user *, size_t, loff_t))SYS(pread64);
+
+	return sys_pread64(fd, buf, count, (loff_t)pos);
+}
+
+asmlinkage int solaris_pwrite(unsigned int fd, char __user *buf, u32 count, u32 pos)
+{
+	ssize_t (*sys_pwrite64)(unsigned int, char __user *, size_t, loff_t) =
+		(ssize_t (*)(unsigned int, char __user *, size_t, loff_t))SYS(pwrite64);
+
+	return sys_pwrite64(fd, buf, count, (loff_t)pos);
+}
+
+/* POSIX.1 names */
+#define _PC_LINK_MAX    1
+#define _PC_MAX_CANON   2
+#define _PC_MAX_INPUT   3
+#define _PC_NAME_MAX    4
+#define _PC_PATH_MAX    5
+#define _PC_PIPE_BUF    6
+#define _PC_NO_TRUNC    7
+#define _PC_VDISABLE    8
+#define _PC_CHOWN_RESTRICTED    9
+/* POSIX.4 names */
+#define _PC_ASYNC_IO    10
+#define _PC_PRIO_IO     11
+#define _PC_SYNC_IO     12
+#define _PC_LAST        12
+
+/* This is not a real and complete implementation yet, just to keep
+ * the easy Solaris binaries happy.
+ */
+asmlinkage int solaris_fpathconf(int fd, int name)
+{
+	int ret;
+
+	switch(name) {
+	case _PC_LINK_MAX:
+		ret = LINK_MAX;
+		break;
+	case _PC_MAX_CANON:
+		ret = MAX_CANON;
+		break;
+	case _PC_MAX_INPUT:
+		ret = MAX_INPUT;
+		break;
+	case _PC_NAME_MAX:
+		ret = NAME_MAX;
+		break;
+	case _PC_PATH_MAX:
+		ret = PATH_MAX;
+		break;
+	case _PC_PIPE_BUF:
+		ret = PIPE_BUF;
+		break;
+	case _PC_CHOWN_RESTRICTED:
+		ret = 1;
+		break;
+	case _PC_NO_TRUNC:
+	case _PC_VDISABLE:
+		ret = 0;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+asmlinkage int solaris_pathconf(u32 path, int name)
+{
+	return solaris_fpathconf(0, name);
+}
+
+/* solaris_llseek returns long long - quite difficult */
+asmlinkage long solaris_llseek(struct pt_regs *regs, u32 off_hi, u32 off_lo, int whence)
+{
+	int (*sys_llseek)(unsigned int, unsigned long, unsigned long, loff_t __user *, unsigned int) =
+		(int (*)(unsigned int, unsigned long, unsigned long, loff_t __user *, unsigned int))SYS(_llseek);
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	loff_t retval;
+	
+	set_fs(KERNEL_DS);
+	ret = sys_llseek((unsigned int)regs->u_regs[UREG_I0], off_hi, off_lo, &retval, whence);
+	set_fs(old_fs);
+	if (ret < 0) return ret;
+	regs->u_regs[UREG_I1] = (u32)retval;
+	return (retval >> 32);
+}
+
+/* Have to mask out all but lower 3 bits */
+asmlinkage int solaris_access(u32 filename, long mode)
+{
+	int (*sys_access)(const char __user *, int) = 
+		(int (*)(const char __user *, int))SYS(access);
+		
+	return sys_access(A(filename), mode & 7);
+}
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
new file mode 100644
index 0000000..cac0a1c
--- /dev/null
+++ b/arch/sparc64/solaris/ioctl.c
@@ -0,0 +1,820 @@
+/* $Id: ioctl.c,v 1.17 2002/02/08 03:57:14 davem Exp $
+ * ioctl.c: Solaris ioctl emulation.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ *
+ * Streams & timod emulation based on code
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ *
+ * 1999-08-19 Implemented solaris 'm' (mag tape) and
+ *            'O' (openprom) ioctls, by Jason Rappleye
+ *             (rappleye@ccr.buffalo.edu)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/syscalls.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/netdevice.h>
+#include <linux/mtio.h>
+#include <linux/time.h>
+#include <linux/compat.h>
+
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+#include <asm/openpromio.h>
+
+#include "conv.h"
+#include "socksys.h"
+
+extern asmlinkage int compat_sys_ioctl(unsigned int fd, unsigned int cmd,
+	u32 arg);
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
+extern int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
+			char __user *data_buf, int data_len, int flags);
+extern int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, int __user *ctl_len,
+			char __user *data_buf, int data_maxlen, int __user *data_len, int *flags);
+
+/* termio* stuff {{{ */
+
+struct solaris_termios {
+	u32	c_iflag;
+	u32	c_oflag;
+	u32	c_cflag;
+	u32	c_lflag;
+	u8	c_cc[19];
+};
+
+struct solaris_termio {
+	u16	c_iflag;
+	u16	c_oflag;
+	u16	c_cflag;
+	u16	c_lflag;
+	s8	c_line;
+	u8	c_cc[8];
+};
+
+struct solaris_termiox {
+	u16	x_hflag;
+	u16	x_cflag;
+	u16	x_rflag[5];
+	u16	x_sflag;
+};
+
+static u32 solaris_to_linux_cflag(u32 cflag)
+{
+	cflag &= 0x7fdff000;
+	if (cflag & 0x200000) {
+		int baud = cflag & 0xf;
+		cflag &= ~0x20000f;
+		switch (baud) {
+		case 0: baud = B57600; break;
+		case 1: baud = B76800; break;
+		case 2: baud = B115200; break;
+		case 3: baud = B153600; break;
+		case 4: baud = B230400; break;
+		case 5: baud = B307200; break;
+		case 6: baud = B460800; break;
+		}
+		cflag |= CBAUDEX | baud;
+	}
+	return cflag;
+}
+
+static u32 linux_to_solaris_cflag(u32 cflag)
+{
+	cflag &= ~(CMSPAR | CIBAUD);
+	if (cflag & CBAUDEX) {
+		int baud = cflag & CBAUD;
+		cflag &= ~CBAUD;
+		switch (baud) {
+		case B57600: baud = 0; break;
+		case B76800: baud = 1; break;
+		case B115200: baud = 2; break;
+		case B153600: baud = 3; break;
+		case B230400: baud = 4; break;
+		case B307200: baud = 5; break;
+		case B460800: baud = 6; break;
+		case B614400: baud = 7; break;
+		case B921600: baud = 8; break;
+#if 0		
+		case B1843200: baud = 9; break;
+#endif
+		}
+		cflag |= 0x200000 | baud;
+	}
+	return cflag;
+}
+
+static inline int linux_to_solaris_termio(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	struct solaris_termio __user *p = A(arg);
+	int ret;
+	
+	ret = sys_ioctl(fd, cmd, (unsigned long)p);
+	if (!ret) {
+		u32 cflag;
+		
+		if (__get_user (cflag, &p->c_cflag))
+			return -EFAULT;
+		cflag = linux_to_solaris_cflag(cflag);
+		if (__put_user (cflag, &p->c_cflag))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+static int solaris_to_linux_termio(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	int ret;
+	struct solaris_termio s;
+	mm_segment_t old_fs = get_fs();
+	
+	if (copy_from_user (&s, (struct solaris_termio __user *)A(arg), sizeof(struct solaris_termio)))
+		return -EFAULT;
+	s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+	set_fs(old_fs);
+	return ret;
+}
+
+static inline int linux_to_solaris_termios(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	int ret;
+	struct solaris_termios s;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);	
+	ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+	set_fs(old_fs);
+	if (!ret) {
+		struct solaris_termios __user *p = A(arg);
+		if (put_user (s.c_iflag, &p->c_iflag) ||
+		    __put_user (s.c_oflag, &p->c_oflag) ||
+		    __put_user (linux_to_solaris_cflag(s.c_cflag), &p->c_cflag) ||
+		    __put_user (s.c_lflag, &p->c_lflag) ||
+		    __copy_to_user (p->c_cc, s.c_cc, 16) ||
+		    __clear_user (p->c_cc + 16, 2))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+static int solaris_to_linux_termios(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	int ret;
+	struct solaris_termios s;
+	struct solaris_termios __user *p = A(arg);
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, TCGETS, (unsigned long)&s);
+	set_fs(old_fs);
+	if (ret) return ret;
+	if (put_user (s.c_iflag, &p->c_iflag) ||
+	    __put_user (s.c_oflag, &p->c_oflag) ||
+	    __put_user (s.c_cflag, &p->c_cflag) ||
+	    __put_user (s.c_lflag, &p->c_lflag) ||
+	    __copy_from_user (s.c_cc, p->c_cc, 16))
+		return -EFAULT;
+	s.c_cflag = solaris_to_linux_cflag(s.c_cflag);
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, cmd, (unsigned long)&s);
+	set_fs(old_fs);
+	return ret;
+}
+
+static inline int solaris_T(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	switch (cmd & 0xff) {
+	case 1: /* TCGETA */
+		return linux_to_solaris_termio(fd, TCGETA, arg);
+	case 2: /* TCSETA */
+		return solaris_to_linux_termio(fd, TCSETA, arg);
+	case 3: /* TCSETAW */
+		return solaris_to_linux_termio(fd, TCSETAW, arg);
+	case 4: /* TCSETAF */
+		return solaris_to_linux_termio(fd, TCSETAF, arg);
+	case 5: /* TCSBRK */
+		return sys_ioctl(fd, TCSBRK, arg);
+	case 6: /* TCXONC */
+		return sys_ioctl(fd, TCXONC, arg);
+	case 7: /* TCFLSH */
+		return sys_ioctl(fd, TCFLSH, arg);
+	case 13: /* TCGETS */
+		return linux_to_solaris_termios(fd, TCGETS, arg);
+	case 14: /* TCSETS */
+		return solaris_to_linux_termios(fd, TCSETS, arg);
+	case 15: /* TCSETSW */
+		return solaris_to_linux_termios(fd, TCSETSW, arg);
+	case 16: /* TCSETSF */
+		return solaris_to_linux_termios(fd, TCSETSF, arg);
+	case 103: /* TIOCSWINSZ */
+		return sys_ioctl(fd, TIOCSWINSZ, arg);
+	case 104: /* TIOCGWINSZ */
+		return sys_ioctl(fd, TIOCGWINSZ, arg);
+	}
+	return -ENOSYS;
+}
+
+static inline int solaris_t(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	switch (cmd & 0xff) {
+	case 20: /* TIOCGPGRP */
+		return sys_ioctl(fd, TIOCGPGRP, arg);
+	case 21: /* TIOCSPGRP */
+		return sys_ioctl(fd, TIOCSPGRP, arg);
+	}
+	return -ENOSYS;
+}
+
+/* }}} */
+
+/* A pseudo STREAMS support {{{ */
+
+struct strioctl {
+	int cmd, timeout, len;
+	u32 data;
+};
+
+struct solaris_si_sockparams {
+	int sp_family;
+	int sp_type;
+	int sp_protocol;
+};
+
+struct solaris_o_si_udata {
+	int tidusize;
+	int addrsize;
+	int optsize;
+	int etsdusize;
+	int servtype;
+	int so_state;
+	int so_options;
+	int tsdusize;
+};
+
+struct solaris_si_udata {
+	int tidusize;
+	int addrsize;
+	int optsize;
+	int etsdusize;
+	int servtype;
+	int so_state;
+	int so_options;
+	int tsdusize;
+	struct solaris_si_sockparams sockparams;
+};
+
+#define SOLARIS_MODULE_TIMOD    0
+#define SOLARIS_MODULE_SOCKMOD  1
+#define SOLARIS_MODULE_MAX      2
+
+static struct module_info {
+        const char *name;
+        /* can be expanded further if needed */
+} module_table[ SOLARIS_MODULE_MAX + 1 ] = {
+        /* the ordering here must match the module numbers above! */
+        { "timod" },
+        { "sockmod" },
+        { NULL }
+};
+
+static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	struct inode *ino;
+	/* I wonder which of these tests are superfluous... --patrik */
+	spin_lock(&current->files->file_lock);
+	if (! current->files->fd[fd] ||
+	    ! current->files->fd[fd]->f_dentry ||
+	    ! (ino = current->files->fd[fd]->f_dentry->d_inode) ||
+	    ! S_ISSOCK(ino->i_mode)) {
+		spin_unlock(&current->files->file_lock);
+		return TBADF;
+	}
+	spin_unlock(&current->files->file_lock);
+	
+	switch (cmd & 0xff) {
+	case 109: /* SI_SOCKPARAMS */
+	{
+		struct solaris_si_sockparams si;
+		if (copy_from_user (&si, A(arg), sizeof(si)))
+			return (EFAULT << 8) | TSYSERR;
+
+		/* Should we modify socket ino->socket_i.ops and type? */
+		return 0;
+	}
+	case 110: /* SI_GETUDATA */
+	{
+		int etsdusize, servtype;
+		struct solaris_si_udata __user *p = A(arg);
+		switch (SOCKET_I(ino)->type) {
+		case SOCK_STREAM:
+			etsdusize = 1;
+			servtype = 2;
+			break;
+		default:
+			etsdusize = -2;
+			servtype = 3;
+			break;
+		}
+		if (put_user(16384, &p->tidusize) ||
+		    __put_user(sizeof(struct sockaddr), &p->addrsize) ||
+		    __put_user(-1, &p->optsize) ||
+		    __put_user(etsdusize, &p->etsdusize) ||
+		    __put_user(servtype, &p->servtype) ||
+		    __put_user(0, &p->so_state) ||
+		    __put_user(0, &p->so_options) ||
+		    __put_user(16384, &p->tsdusize) ||
+		    __put_user(SOCKET_I(ino)->ops->family, &p->sockparams.sp_family) ||
+		    __put_user(SOCKET_I(ino)->type, &p->sockparams.sp_type) ||
+		    __put_user(SOCKET_I(ino)->ops->family, &p->sockparams.sp_protocol))
+			return (EFAULT << 8) | TSYSERR;
+		return 0;
+	}
+	case 101: /* O_SI_GETUDATA */
+	{
+		int etsdusize, servtype;
+		struct solaris_o_si_udata __user *p = A(arg);
+		switch (SOCKET_I(ino)->type) {
+		case SOCK_STREAM:
+			etsdusize = 1;
+			servtype = 2;
+			break;
+		default:
+			etsdusize = -2;
+			servtype = 3;
+			break;
+		}
+		if (put_user(16384, &p->tidusize) ||
+		    __put_user(sizeof(struct sockaddr), &p->addrsize) ||
+		    __put_user(-1, &p->optsize) ||
+		    __put_user(etsdusize, &p->etsdusize) ||
+		    __put_user(servtype, &p->servtype) ||
+		    __put_user(0, &p->so_state) ||
+		    __put_user(0, &p->so_options) ||
+		    __put_user(16384, &p->tsdusize))
+			return (EFAULT << 8) | TSYSERR;
+		return 0;
+	}
+	case 102: /* SI_SHUTDOWN */
+	case 103: /* SI_LISTEN */
+	case 104: /* SI_SETMYNAME */
+	case 105: /* SI_SETPEERNAME */
+	case 106: /* SI_GETINTRANSIT */
+	case 107: /* SI_TCL_LINK */
+	case 108: /* SI_TCL_UNLINK */
+		;
+	}
+	return TNOTSUPPORT;
+}
+
+static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg,
+                                    int len, int __user *len_p)
+{
+	int ret;
+		
+	switch (cmd & 0xff) {
+	case 141: /* TI_OPTMGMT */
+	{
+		int i;
+		u32 prim;
+		SOLD("TI_OPMGMT entry");
+		ret = timod_putmsg(fd, A(arg), len, NULL, -1, 0);
+		SOLD("timod_putmsg() returned");
+		if (ret)
+			return (-ret << 8) | TSYSERR;
+		i = MSG_HIPRI;
+		SOLD("calling timod_getmsg()");
+		ret = timod_getmsg(fd, A(arg), len, len_p, NULL, -1, NULL, &i);
+		SOLD("timod_getmsg() returned");
+		if (ret)
+			return (-ret << 8) | TSYSERR;
+		SOLD("ret ok");
+		if (get_user(prim, (u32 __user *)A(arg)))
+			return (EFAULT << 8) | TSYSERR;
+		SOLD("got prim");
+		if (prim == T_ERROR_ACK) {
+			u32 tmp, tmp2;
+			SOLD("prim is T_ERROR_ACK");
+			if (get_user(tmp, (u32 __user *)A(arg)+3) ||
+			    get_user(tmp2, (u32 __user *)A(arg)+2))
+				return (EFAULT << 8) | TSYSERR;
+			return (tmp2 << 8) | tmp;
+		}
+		SOLD("TI_OPMGMT return 0");
+		return 0;
+	}
+	case 142: /* TI_BIND */
+	{
+		int i;
+		u32 prim;
+		SOLD("TI_BIND entry");
+		ret = timod_putmsg(fd, A(arg), len, NULL, -1, 0);
+		SOLD("timod_putmsg() returned");
+		if (ret)
+			return (-ret << 8) | TSYSERR;
+		len = 1024; /* Solaris allows arbitrary return size */
+		i = MSG_HIPRI;
+		SOLD("calling timod_getmsg()");
+		ret = timod_getmsg(fd, A(arg), len, len_p, NULL, -1, NULL, &i);
+		SOLD("timod_getmsg() returned");
+		if (ret)
+			return (-ret << 8) | TSYSERR;
+		SOLD("ret ok");
+		if (get_user(prim, (u32 __user *)A(arg)))
+			return (EFAULT << 8) | TSYSERR;
+		SOLD("got prim");
+		if (prim == T_ERROR_ACK) {
+			u32 tmp, tmp2;
+			SOLD("prim is T_ERROR_ACK");
+			if (get_user(tmp, (u32 __user *)A(arg)+3) ||
+			    get_user(tmp2, (u32 __user *)A(arg)+2))
+				return (EFAULT << 8) | TSYSERR;
+			return (tmp2 << 8) | tmp;
+		}
+		SOLD("no ERROR_ACK requested");
+		if (prim != T_OK_ACK)
+			return TBADSEQ;
+		SOLD("OK_ACK requested");
+		i = MSG_HIPRI;
+		SOLD("calling timod_getmsg()");
+		ret = timod_getmsg(fd, A(arg), len, len_p, NULL, -1, NULL, &i);
+		SOLD("timod_getmsg() returned");
+		if (ret)
+			return (-ret << 8) | TSYSERR;
+		SOLD("TI_BIND return ok");
+		return 0;
+	}
+	case 140: /* TI_GETINFO */
+	case 143: /* TI_UNBIND */
+	case 144: /* TI_GETMYNAME */
+	case 145: /* TI_GETPEERNAME */
+	case 146: /* TI_SETMYNAME */
+	case 147: /* TI_SETPEERNAME */
+		;
+	}
+	return TNOTSUPPORT;
+}
+
+static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd, u32 arg)
+{
+	char *p;
+	int ret;
+	mm_segment_t old_fs;
+	struct strioctl si;
+	struct inode *ino;
+        struct sol_socket_struct *sock;
+        struct module_info *mi;
+
+        ino = filp->f_dentry->d_inode;
+        if (!S_ISSOCK(ino->i_mode))
+		return -EBADF;
+        sock = filp->private_data;
+        if (! sock) {
+                printk("solaris_S: NULL private_data\n");
+                return -EBADF;
+        }
+        if (sock->magic != SOLARIS_SOCKET_MAGIC) {
+                printk("solaris_S: invalid magic\n");
+                return -EBADF;
+        }
+        
+
+	switch (cmd & 0xff) {
+	case 1: /* I_NREAD */
+		return -ENOSYS;
+	case 2: /* I_PUSH */
+        {
+		p = getname (A(arg));
+		if (IS_ERR (p))
+			return PTR_ERR(p);
+                ret = -EINVAL;
+                for (mi = module_table; mi->name; mi++) {
+                        if (strcmp(mi->name, p) == 0) {
+                                sol_module m;
+                                if (sock->modcount >= MAX_NR_STREAM_MODULES) {
+                                        ret = -ENXIO;
+                                        break;
+                                }
+                                m = (sol_module) (mi - module_table);
+                                sock->module[sock->modcount++] = m;
+                                ret = 0;
+                                break;
+                        }
+                }
+		putname (p);
+		return ret;
+        }
+	case 3: /* I_POP */
+                if (sock->modcount <= 0) return -EINVAL;
+                sock->modcount--;
+		return 0;
+        case 4: /* I_LOOK */
+        {
+        	const char *p;
+                if (sock->modcount <= 0) return -EINVAL;
+                p = module_table[(unsigned)sock->module[sock->modcount]].name;
+                if (copy_to_user (A(arg), p, strlen(p)))
+                	return -EFAULT;
+                return 0;
+        }
+	case 5: /* I_FLUSH */
+		return 0;
+	case 8: /* I_STR */
+		if (copy_from_user(&si, A(arg), sizeof(struct strioctl)))
+			return -EFAULT;
+                /* We ignore what module is actually at the top of stack. */
+		switch ((si.cmd >> 8) & 0xff) {
+		case 'I':
+                        return solaris_sockmod(fd, si.cmd, si.data);
+		case 'T':
+                        return solaris_timod(fd, si.cmd, si.data, si.len,
+				&((struct strioctl __user *)A(arg))->len);
+		default:
+			return solaris_ioctl(fd, si.cmd, si.data);
+		}
+	case 9: /* I_SETSIG */
+		return sys_ioctl(fd, FIOSETOWN, current->pid);
+	case 10: /* I_GETSIG */
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		sys_ioctl(fd, FIOGETOWN, (unsigned long)&ret);
+		set_fs(old_fs);
+		if (ret == current->pid) return 0x3ff;
+		else return -EINVAL;
+	case 11: /* I_FIND */
+        {
+                int i;
+		p = getname (A(arg));
+		if (IS_ERR (p))
+			return PTR_ERR(p);
+                ret = 0;
+                for (i = 0; i < sock->modcount; i++) {
+                        unsigned m = sock->module[i];
+                        if (strcmp(module_table[m].name, p) == 0) {
+                                ret = 1;
+                                break;
+                        } 
+                }
+		putname (p);
+		return ret;
+        }
+	case 19: /* I_SWROPT */
+	case 32: /* I_SETCLTIME */
+		return 0;	/* Lie */
+	}
+	return -ENOSYS;
+}
+
+static inline int solaris_s(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	switch (cmd & 0xff) {
+	case 0: /* SIOCSHIWAT */
+	case 2: /* SIOCSLOWAT */
+		return 0; /* We don't support them */
+	case 1: /* SIOCGHIWAT */
+	case 3: /* SIOCGLOWAT */
+		if (put_user (0, (u32 __user *)A(arg)))
+			return -EFAULT;
+		return 0; /* Lie */
+	case 7: /* SIOCATMARK */
+		return sys_ioctl(fd, SIOCATMARK, arg);
+	case 8: /* SIOCSPGRP */
+		return sys_ioctl(fd, SIOCSPGRP, arg);
+	case 9: /* SIOCGPGRP */
+		return sys_ioctl(fd, SIOCGPGRP, arg);
+	}
+	return -ENOSYS;
+}
+
+static inline int solaris_r(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	switch (cmd & 0xff) {
+	case 10: /* SIOCADDRT */
+		return compat_sys_ioctl(fd, SIOCADDRT, arg);
+	case 11: /* SIOCDELRT */
+		return compat_sys_ioctl(fd, SIOCDELRT, arg);
+	}
+	return -ENOSYS;
+}
+
+static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	switch (cmd & 0xff) {
+	case 12: /* SIOCSIFADDR */
+		return compat_sys_ioctl(fd, SIOCSIFADDR, arg);
+	case 13: /* SIOCGIFADDR */
+		return compat_sys_ioctl(fd, SIOCGIFADDR, arg);
+	case 14: /* SIOCSIFDSTADDR */
+		return compat_sys_ioctl(fd, SIOCSIFDSTADDR, arg);
+	case 15: /* SIOCGIFDSTADDR */
+		return compat_sys_ioctl(fd, SIOCGIFDSTADDR, arg);
+	case 16: /* SIOCSIFFLAGS */
+		return compat_sys_ioctl(fd, SIOCSIFFLAGS, arg);
+	case 17: /* SIOCGIFFLAGS */
+		return compat_sys_ioctl(fd, SIOCGIFFLAGS, arg);
+	case 18: /* SIOCSIFMEM */
+		return compat_sys_ioctl(fd, SIOCSIFMEM, arg);
+	case 19: /* SIOCGIFMEM */
+		return compat_sys_ioctl(fd, SIOCGIFMEM, arg);
+	case 20: /* SIOCGIFCONF */
+		return compat_sys_ioctl(fd, SIOCGIFCONF, arg);
+	case 21: /* SIOCSIFMTU */
+		return compat_sys_ioctl(fd, SIOCSIFMTU, arg);
+	case 22: /* SIOCGIFMTU */
+		return compat_sys_ioctl(fd, SIOCGIFMTU, arg);
+	case 23: /* SIOCGIFBRDADDR */
+		return compat_sys_ioctl(fd, SIOCGIFBRDADDR, arg);
+	case 24: /* SIOCSIFBRDADDR */
+		return compat_sys_ioctl(fd, SIOCSIFBRDADDR, arg);
+	case 25: /* SIOCGIFNETMASK */
+		return compat_sys_ioctl(fd, SIOCGIFNETMASK, arg);
+	case 26: /* SIOCSIFNETMASK */
+		return compat_sys_ioctl(fd, SIOCSIFNETMASK, arg);
+	case 27: /* SIOCGIFMETRIC */
+		return compat_sys_ioctl(fd, SIOCGIFMETRIC, arg);
+	case 28: /* SIOCSIFMETRIC */
+		return compat_sys_ioctl(fd, SIOCSIFMETRIC, arg);
+	case 30: /* SIOCSARP */
+		return compat_sys_ioctl(fd, SIOCSARP, arg);
+	case 31: /* SIOCGARP */
+		return compat_sys_ioctl(fd, SIOCGARP, arg);
+	case 32: /* SIOCDARP */
+		return compat_sys_ioctl(fd, SIOCDARP, arg);
+	case 52: /* SIOCGETNAME */
+	case 53: /* SIOCGETPEER */
+		{
+			struct sockaddr uaddr;
+			int uaddr_len = sizeof(struct sockaddr), ret;
+			long args[3];
+			mm_segment_t old_fs = get_fs();
+			int (*sys_socketcall)(int, unsigned long *) =
+				(int (*)(int, unsigned long *))SYS(socketcall);
+			
+			args[0] = fd; args[1] = (long)&uaddr; args[2] = (long)&uaddr_len;
+			set_fs(KERNEL_DS);
+			ret = sys_socketcall(((cmd & 0xff) == 52) ? SYS_GETSOCKNAME : SYS_GETPEERNAME,
+					args);
+			set_fs(old_fs);
+			if (ret >= 0) {
+				if (copy_to_user(A(arg), &uaddr, uaddr_len))
+					return -EFAULT;
+			}
+			return ret;
+		}
+#if 0		
+	case 86: /* SIOCSOCKSYS */
+		return socksys_syscall(fd, arg);
+#endif		
+	case 87: /* SIOCGIFNUM */
+		{
+			struct net_device *d;
+			int i = 0;
+			
+			read_lock_bh(&dev_base_lock);
+			for (d = dev_base; d; d = d->next) i++;
+			read_unlock_bh(&dev_base_lock);
+
+			if (put_user (i, (int __user *)A(arg)))
+				return -EFAULT;
+			return 0;
+		}
+	}
+	return -ENOSYS;
+}
+
+static int solaris_m(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	int ret;
+
+	switch (cmd & 0xff) {
+	case 1: /* MTIOCTOP */
+		ret = sys_ioctl(fd, MTIOCTOP, (unsigned long)&arg);
+		break;
+	case 2: /* MTIOCGET */
+		ret = sys_ioctl(fd, MTIOCGET, (unsigned long)&arg);
+		break;
+	case 3: /* MTIOCGETDRIVETYPE */
+	case 4: /* MTIOCPERSISTENT */
+	case 5: /* MTIOCPERSISTENTSTATUS */
+	case 6: /* MTIOCLRERR */
+	case 7: /* MTIOCGUARANTEEDORDER */
+	case 8: /* MTIOCRESERVE */
+	case 9: /* MTIOCRELEASE */
+	case 10: /* MTIOCFORCERESERVE */
+	case 13: /* MTIOCSTATE */
+	case 14: /* MTIOCREADIGNOREILI */
+	case 15: /* MTIOCREADIGNOREEOFS */
+	case 16: /* MTIOCSHORTFMK */
+	default:
+		ret = -ENOSYS; /* linux doesn't support these */
+		break;
+	};
+
+	return ret;
+}
+
+static int solaris_O(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	int ret = -EINVAL;
+
+	switch (cmd & 0xff) {
+	case 1: /* OPROMGETOPT */
+		ret = sys_ioctl(fd, OPROMGETOPT, arg);
+		break;
+	case 2: /* OPROMSETOPT */
+		ret = sys_ioctl(fd, OPROMSETOPT, arg);
+		break;
+	case 3: /* OPROMNXTOPT */
+		ret = sys_ioctl(fd, OPROMNXTOPT, arg);
+		break;
+	case 4: /* OPROMSETOPT2 */
+		ret = sys_ioctl(fd, OPROMSETOPT2, arg);
+		break;
+	case 5: /* OPROMNEXT */
+		ret = sys_ioctl(fd, OPROMNEXT, arg);
+		break;
+	case 6: /* OPROMCHILD */
+		ret = sys_ioctl(fd, OPROMCHILD, arg);
+		break;
+	case 7: /* OPROMGETPROP */
+		ret = sys_ioctl(fd, OPROMGETPROP, arg);
+		break;
+	case 8: /* OPROMNXTPROP */
+		ret = sys_ioctl(fd, OPROMNXTPROP, arg);
+		break;
+	case 9: /* OPROMU2P */
+		ret = sys_ioctl(fd, OPROMU2P, arg);
+		break;
+	case 10: /* OPROMGETCONS */
+		ret = sys_ioctl(fd, OPROMGETCONS, arg);
+		break;
+	case 11: /* OPROMGETFBNAME */
+		ret = sys_ioctl(fd, OPROMGETFBNAME, arg);
+		break;
+	case 12: /* OPROMGETBOOTARGS */
+		ret = sys_ioctl(fd, OPROMGETBOOTARGS, arg);
+		break;
+	case 13: /* OPROMGETVERSION */
+	case 14: /* OPROMPATH2DRV */
+	case 15: /* OPROMDEV2PROMNAME */
+	case 16: /* OPROMPROM2DEVNAME */
+	case 17: /* OPROMGETPROPLEN */
+	default:
+		ret = -EINVAL;
+		break;
+	};
+	return ret;
+}
+
+/* }}} */
+
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	struct file *filp;
+	int error = -EBADF;
+
+	filp = fget(fd);
+	if (!filp)
+		goto out;
+
+	lock_kernel();
+	error = -EFAULT;
+	switch ((cmd >> 8) & 0xff) {
+	case 'S': error = solaris_S(filp, fd, cmd, arg); break;
+	case 'T': error = solaris_T(fd, cmd, arg); break;
+	case 'i': error = solaris_i(fd, cmd, arg); break;
+	case 'r': error = solaris_r(fd, cmd, arg); break;
+	case 's': error = solaris_s(fd, cmd, arg); break;
+	case 't': error = solaris_t(fd, cmd, arg); break;
+	case 'f': error = sys_ioctl(fd, cmd, arg); break;
+	case 'm': error = solaris_m(fd, cmd, arg); break;
+	case 'O': error = solaris_O(fd, cmd, arg); break;
+	default:
+		error = -ENOSYS;
+		break;
+	}
+	unlock_kernel();
+	fput(filp);
+out:
+	if (error == -ENOSYS) {
+		unsigned char c = cmd>>8;
+		
+		if (c < ' ' || c > 126) c = '.';
+		printk("solaris_ioctl: Unknown cmd fd(%d) cmd(%08x '%c') arg(%08x)\n",
+		       (int)fd, (unsigned int)cmd, c, (unsigned int)arg);
+		error = -EINVAL;
+	}
+	return error;
+}
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
new file mode 100644
index 0000000..8cef5fd
--- /dev/null
+++ b/arch/sparc64/solaris/ipc.c
@@ -0,0 +1,127 @@
+/* $Id: ipc.c,v 1.5 1999/12/09 00:41:00 davem Exp $
+ * ipc.c: Solaris IPC emulation
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/ipc.h>
+
+#include "conv.h"
+
+struct solaris_ipc_perm {
+	s32	uid;
+	s32	gid;
+	s32	cuid;
+	s32	cgid;
+	u32	mode;
+	u32	seq;
+	int	key;
+	s32	pad[4];
+};
+
+struct solaris_shmid_ds {
+	struct solaris_ipc_perm	shm_perm;
+	int			shm_segsz;
+	u32			shm_amp;
+	unsigned short		shm_lkcnt;
+	char			__padxx[2];
+	s32			shm_lpid;
+	s32			shm_cpid;
+	u32			shm_nattch;
+	u32			shm_cnattch;
+	s32			shm_atime;
+	s32			shm_pad1;
+	s32			shm_dtime;
+	s32			shm_pad2;
+	s32			shm_ctime;
+	s32			shm_pad3;
+	unsigned short		shm_cv;
+	char			shm_pad4[2];
+	u32			shm_sptas;
+	s32			shm_pad5[2];
+};
+
+asmlinkage long solaris_shmsys(int cmd, u32 arg1, u32 arg2, u32 arg3)
+{
+	int (*sys_ipc)(unsigned,int,int,unsigned long,void __user *,long) = 
+		(int (*)(unsigned,int,int,unsigned long,void __user *,long))SYS(ipc);
+	mm_segment_t old_fs;
+	unsigned long raddr;
+	int ret;
+		
+	switch (cmd) {
+	case 0: /* shmat */
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = sys_ipc(SHMAT, arg1, arg3 & ~0x4000, (unsigned long)&raddr, A(arg2), 0);
+		set_fs(old_fs);
+		if (ret >= 0) return (u32)raddr;
+		else return ret;
+	case 1: /* shmctl */
+		switch (arg2) {
+		case 3: /* SHM_LOCK */
+		case 4: /* SHM_UNLOCK */
+			return sys_ipc(SHMCTL, arg1, (arg2 == 3) ? SHM_LOCK : SHM_UNLOCK, 0, NULL, 0);
+		case 10: /* IPC_RMID */
+			return sys_ipc(SHMCTL, arg1, IPC_RMID, 0, NULL, 0);
+		case 11: /* IPC_SET */
+			{
+				struct shmid_ds s;
+				struct solaris_shmid_ds __user *p = A(arg3);
+				
+				if (get_user (s.shm_perm.uid, &p->shm_perm.uid) ||
+				    __get_user (s.shm_perm.gid, &p->shm_perm.gid) || 
+				    __get_user (s.shm_perm.mode, &p->shm_perm.mode))
+					return -EFAULT;
+				old_fs = get_fs();
+				set_fs(KERNEL_DS);
+				ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0);
+				set_fs(old_fs);
+				return ret;
+			}
+		case 12: /* IPC_STAT */
+			{
+				struct shmid_ds s;
+				struct solaris_shmid_ds __user *p = A(arg3);
+				
+				old_fs = get_fs();
+				set_fs(KERNEL_DS);
+				ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0);
+				set_fs(old_fs);
+				if (put_user (s.shm_perm.uid, &(p->shm_perm.uid)) ||
+				    __put_user (s.shm_perm.gid, &(p->shm_perm.gid)) || 
+				    __put_user (s.shm_perm.cuid, &(p->shm_perm.cuid)) ||
+				    __put_user (s.shm_perm.cgid, &(p->shm_perm.cgid)) || 
+				    __put_user (s.shm_perm.mode, &(p->shm_perm.mode)) ||
+				    __put_user (s.shm_perm.seq, &(p->shm_perm.seq)) ||
+				    __put_user (s.shm_perm.key, &(p->shm_perm.key)) ||
+				    __put_user (s.shm_segsz, &(p->shm_segsz)) ||
+				    __put_user (s.shm_lpid, &(p->shm_lpid)) ||
+				    __put_user (s.shm_cpid, &(p->shm_cpid)) ||
+				    __put_user (s.shm_nattch, &(p->shm_nattch)) ||
+				    __put_user (s.shm_atime, &(p->shm_atime)) ||
+				    __put_user (s.shm_dtime, &(p->shm_dtime)) ||
+				    __put_user (s.shm_ctime, &(p->shm_ctime)))
+					return -EFAULT;
+				return ret;
+			}
+		default: return -EINVAL;
+		}
+	case 2: /* shmdt */
+		return sys_ipc(SHMDT, 0, 0, 0, A(arg1), 0);
+	case 3: /* shmget */
+		return sys_ipc(SHMGET, arg1, arg2, arg3, NULL, 0);
+	}
+	return -EINVAL;
+}
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
new file mode 100644
index 0000000..15b4cfe
--- /dev/null
+++ b/arch/sparc64/solaris/misc.c
@@ -0,0 +1,784 @@
+/* $Id: misc.c,v 1.36 2002/02/09 19:49:31 davem Exp $
+ * misc.c: Miscellaneous syscall emulation for Solaris
+ *
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h> 
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/utsname.h>
+#include <linux/limits.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/timex.h>
+#include <linux/major.h>
+#include <linux/compat.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#include <asm/smp.h>
+
+#include "conv.h"
+
+/* Conversion from Linux to Solaris errnos. 0-34 are identity mapped.
+   Some Linux errnos (EPROCLIM, EDOTDOT, ERREMOTE, EUCLEAN, ENOTNAM, 
+   ENAVAIL, EISNAM, EREMOTEIO, ENOMEDIUM, EMEDIUMTYPE) have no Solaris
+   equivalents. I return EINVAL in that case, which is very wrong. If
+   someone suggest a better value for them, you're welcomed.
+   On the other side, Solaris ECANCELED and ENOTSUP have no Linux equivalents,
+   but that doesn't matter here. --jj */
+int solaris_err_table[] = {
+/* 0 */  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+/* 10 */  10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+/* 20 */  20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+/* 30 */  30, 31, 32, 33, 34, 22, 150, 149, 95, 96,
+/* 40 */  97, 98, 99, 120, 121, 122, 123, 124, 125, 126, 
+/* 50 */ 127, 128, 129, 130, 131, 132, 133, 134, 143, 144,
+/* 60 */ 145, 146, 90, 78, 147, 148, 93, 22, 94, 49,
+/* 70 */ 151, 66, 60, 62, 63, 35, 77, 36, 45, 46, 
+/* 80 */ 64, 22, 67, 68, 69, 70, 71, 74, 22, 82, 
+/* 90 */ 89, 92, 79, 81, 37, 38, 39, 40, 41, 42,
+/* 100 */ 43, 44, 50, 51, 52, 53, 54, 55, 56, 57,
+/* 110 */ 87, 61, 84, 65, 83, 80, 91, 22, 22, 22,
+/* 120 */ 22, 22, 88, 86, 85, 22, 22,
+};
+
+#define SOLARIS_NR_OPEN	256
+
+static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 off)
+{
+	struct file *file = NULL;
+	unsigned long retval, ret_type;
+
+	/* Do we need it here? */
+	set_personality(PER_SVR4);
+	if (flags & MAP_NORESERVE) {
+		static int cnt;
+		
+		if (cnt < 5) {
+			printk("%s:  unimplemented Solaris MAP_NORESERVE mmap() flag\n",
+			       current->comm);
+			cnt++;
+		}
+		flags &= ~MAP_NORESERVE;
+	}
+	retval = -EBADF;
+	if(!(flags & MAP_ANONYMOUS)) {
+		if(fd >= SOLARIS_NR_OPEN)
+			goto out;
+ 		file = fget(fd);
+		if (!file)
+			goto out;
+		else {
+			struct inode * inode = file->f_dentry->d_inode;
+			if(imajor(inode) == MEM_MAJOR &&
+			   iminor(inode) == 5) {
+				flags |= MAP_ANONYMOUS;
+				fput(file);
+				file = NULL;
+			}
+		}
+	}
+
+	retval = -EINVAL;
+	len = PAGE_ALIGN(len);
+	if(!(flags & MAP_FIXED))
+		addr = 0;
+	else if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
+		goto out_putf;
+	ret_type = flags & _MAP_NEW;
+	flags &= ~_MAP_NEW;
+
+	down_write(&current->mm->mmap_sem);
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	retval = do_mmap(file,
+			 (unsigned long) addr, (unsigned long) len,
+			 (unsigned long) prot, (unsigned long) flags, off);
+	up_write(&current->mm->mmap_sem);
+	if(!ret_type)
+		retval = ((retval < 0xf0000000) ? 0 : retval);
+	                        
+out_putf:
+	if (file)
+		fput(file);
+out:
+	return (u32) retval;
+}
+
+asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+{
+	return do_solaris_mmap(addr, len, prot, flags, fd, (u64) off);
+}
+
+asmlinkage u32 solaris_mmap64(struct pt_regs *regs, u32 len, u32 prot, u32 flags, u32 fd, u32 offhi)
+{
+	u32 offlo;
+	
+	if (regs->u_regs[UREG_G1]) {
+		if (get_user (offlo, (u32 __user *)(long)((u32)regs->u_regs[UREG_I6] + 0x5c)))
+			return -EFAULT;
+	} else {
+		if (get_user (offlo, (u32 __user *)(long)((u32)regs->u_regs[UREG_I6] + 0x60)))
+			return -EFAULT;
+	}
+	return do_solaris_mmap((u32)regs->u_regs[UREG_I0], len, prot, flags, fd, (((u64)offhi)<<32)|offlo);
+}
+
+asmlinkage int solaris_brk(u32 brk)
+{
+	int (*sunos_brk)(u32) = (int (*)(u32))SUNOS(17);
+	
+	return sunos_brk(brk);
+}
+
+static int __set_utsfield(char __user *to, int to_size,
+			  const char *from, int from_size,
+			  int dotchop, int countfrom)
+{
+	int len = countfrom ? (to_size > from_size ?
+			       from_size : to_size) : to_size;
+	int off;
+
+	if (copy_to_user(to, from, len))
+		return -EFAULT;
+
+	off = len < to_size? len: len - 1;
+	if (dotchop) {
+		const char *p = strnchr(from, len, '.');
+		if (p) off = p - from;
+	}
+
+	if (__put_user('\0', to + off))
+		return -EFAULT;
+
+	return 0;
+}
+
+#define set_utsfield(to, from, dotchop, countfrom) \
+	__set_utsfield((to), sizeof(to), \
+		       (from), sizeof(from), \
+		       (dotchop), (countfrom))
+
+struct sol_uname {
+	char sysname[9];
+	char nodename[9];
+	char release[9];
+	char version[9];
+	char machine[9];
+};
+
+struct sol_utsname {
+	char sysname[257];
+	char nodename[257];
+	char release[257];
+	char version[257];
+	char machine[257];
+};
+
+static char *machine(void)
+{
+	switch (sparc_cpu_model) {
+	case sun4: return "sun4";
+	case sun4c: return "sun4c";
+	case sun4e: return "sun4e";
+	case sun4m: return "sun4m";
+	case sun4d: return "sun4d";
+	case sun4u: return "sun4u";
+	default: return "sparc";
+	}
+}
+
+static char *platform(char *buffer)
+{
+	int len;
+
+	*buffer = 0;
+	len = prom_getproperty(prom_root_node, "name", buffer, 256);
+	if(len > 0)
+		buffer[len] = 0;
+	if (*buffer) {
+		char *p;
+
+		for (p = buffer; *p; p++)
+			if (*p == '/' || *p == ' ') *p = '_';
+		return buffer;
+	}
+
+	return "sun4u";
+}
+
+static char *serial(char *buffer)
+{
+	int node = prom_getchild(prom_root_node);
+	int len;
+
+	node = prom_searchsiblings(node, "options");
+	*buffer = 0;
+	len = prom_getproperty(node, "system-board-serial#", buffer, 256);
+	if(len > 0)
+		buffer[len] = 0;
+	if (!*buffer)
+		return "4512348717234";
+	else
+		return buffer;
+}
+
+asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
+{
+	struct sol_uname __user *v = A(buf);
+	int err;
+
+	switch (which) {
+	case 0:	/* old uname */
+		/* Let's cheat */
+		err  = set_utsfield(v->sysname, "SunOS", 1, 0);
+		down_read(&uts_sem);
+		err |= set_utsfield(v->nodename, system_utsname.nodename,
+				    1, 1);
+		up_read(&uts_sem);
+		err |= set_utsfield(v->release, "2.6", 0, 0);
+		err |= set_utsfield(v->version, "Generic", 0, 0);
+		err |= set_utsfield(v->machine, machine(), 0, 0);
+		return (err ? -EFAULT : 0);
+	case 2: /* ustat */
+		return -ENOSYS;
+	case 3: /* fusers */
+		return -ENOSYS;
+	default:
+		return -ENOSYS;
+	}
+}
+
+asmlinkage int solaris_utsname(u32 buf)
+{
+	struct sol_utsname __user *v = A(buf);
+	int err;
+
+	/* Why should we not lie a bit? */
+	down_read(&uts_sem);
+	err  = set_utsfield(v->sysname, "SunOS", 0, 0);
+	err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1);
+	err |= set_utsfield(v->release, "5.6", 0, 0);
+	err |= set_utsfield(v->version, "Generic", 0, 0);
+	err |= set_utsfield(v->machine, machine(), 0, 0);
+	up_read(&uts_sem);
+
+	return (err ? -EFAULT : 0);
+}
+
+#define SI_SYSNAME		1       /* return name of operating system */
+#define SI_HOSTNAME		2       /* return name of node */
+#define SI_RELEASE		3       /* return release of operating system */
+#define SI_VERSION		4       /* return version field of utsname */
+#define SI_MACHINE		5       /* return kind of machine */
+#define SI_ARCHITECTURE		6       /* return instruction set arch */
+#define SI_HW_SERIAL		7       /* return hardware serial number */
+#define SI_HW_PROVIDER		8       /* return hardware manufacturer */
+#define SI_SRPC_DOMAIN		9       /* return secure RPC domain */
+#define SI_PLATFORM		513     /* return platform identifier */
+
+asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
+{
+	char *p, *q, *r;
+	char buffer[256];
+	int len;
+	
+	/* Again, we cheat :)) */
+	switch (cmd) {
+	case SI_SYSNAME: r = "SunOS"; break;
+	case SI_HOSTNAME:
+		r = buffer + 256;
+		down_read(&uts_sem);
+		for (p = system_utsname.nodename, q = buffer; 
+		     q < r && *p && *p != '.'; *q++ = *p++);
+		up_read(&uts_sem);
+		*q = 0;
+		r = buffer;
+		break;
+	case SI_RELEASE: r = "5.6"; break;
+	case SI_MACHINE: r = machine(); break;
+	case SI_ARCHITECTURE: r = "sparc"; break;
+	case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
+	case SI_HW_SERIAL: r = serial(buffer); break;
+	case SI_PLATFORM: r = platform(buffer); break;
+	case SI_SRPC_DOMAIN: r = ""; break;
+	case SI_VERSION: r = "Generic"; break;
+	default: return -EINVAL;
+	}
+	len = strlen(r) + 1;
+	if (count < len) {
+		if (copy_to_user(A(buf), r, count - 1) ||
+		    __put_user(0, (char __user *)A(buf) + count - 1))
+			return -EFAULT;
+	} else {
+		if (copy_to_user(A(buf), r, len))
+			return -EFAULT;
+	}
+	return len;
+}
+
+#define	SOLARIS_CONFIG_NGROUPS			2
+#define	SOLARIS_CONFIG_CHILD_MAX		3
+#define	SOLARIS_CONFIG_OPEN_FILES		4
+#define	SOLARIS_CONFIG_POSIX_VER		5
+#define	SOLARIS_CONFIG_PAGESIZE			6
+#define	SOLARIS_CONFIG_CLK_TCK			7
+#define	SOLARIS_CONFIG_XOPEN_VER		8
+#define	SOLARIS_CONFIG_PROF_TCK			10
+#define	SOLARIS_CONFIG_NPROC_CONF		11
+#define	SOLARIS_CONFIG_NPROC_ONLN		12
+#define	SOLARIS_CONFIG_AIO_LISTIO_MAX		13
+#define	SOLARIS_CONFIG_AIO_MAX			14
+#define	SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX	15
+#define	SOLARIS_CONFIG_DELAYTIMER_MAX		16
+#define	SOLARIS_CONFIG_MQ_OPEN_MAX		17
+#define	SOLARIS_CONFIG_MQ_PRIO_MAX		18
+#define	SOLARIS_CONFIG_RTSIG_MAX		19
+#define	SOLARIS_CONFIG_SEM_NSEMS_MAX		20
+#define	SOLARIS_CONFIG_SEM_VALUE_MAX		21
+#define	SOLARIS_CONFIG_SIGQUEUE_MAX		22
+#define	SOLARIS_CONFIG_SIGRT_MIN		23
+#define	SOLARIS_CONFIG_SIGRT_MAX		24
+#define	SOLARIS_CONFIG_TIMER_MAX		25
+#define	SOLARIS_CONFIG_PHYS_PAGES		26
+#define	SOLARIS_CONFIG_AVPHYS_PAGES		27
+
+asmlinkage int solaris_sysconf(int id)
+{
+	switch (id) {
+	case SOLARIS_CONFIG_NGROUPS:	return NGROUPS_MAX;
+	case SOLARIS_CONFIG_CHILD_MAX:	return CHILD_MAX;
+	case SOLARIS_CONFIG_OPEN_FILES:	return OPEN_MAX;
+	case SOLARIS_CONFIG_POSIX_VER:	return 199309;
+	case SOLARIS_CONFIG_PAGESIZE:	return PAGE_SIZE;
+	case SOLARIS_CONFIG_XOPEN_VER:	return 3;
+	case SOLARIS_CONFIG_CLK_TCK:
+	case SOLARIS_CONFIG_PROF_TCK:
+		return sparc64_get_clock_tick(smp_processor_id());
+#ifdef CONFIG_SMP	
+	case SOLARIS_CONFIG_NPROC_CONF:	return NR_CPUS;
+	case SOLARIS_CONFIG_NPROC_ONLN:	return num_online_cpus();
+#else
+	case SOLARIS_CONFIG_NPROC_CONF:	return 1;
+	case SOLARIS_CONFIG_NPROC_ONLN:	return 1;
+#endif
+	case SOLARIS_CONFIG_SIGRT_MIN:		return 37;
+	case SOLARIS_CONFIG_SIGRT_MAX:		return 44;
+	case SOLARIS_CONFIG_PHYS_PAGES:
+	case SOLARIS_CONFIG_AVPHYS_PAGES:
+		{
+			struct sysinfo s;
+			
+			si_meminfo(&s);
+			if (id == SOLARIS_CONFIG_PHYS_PAGES)
+				return s.totalram >>= PAGE_SHIFT;
+			else
+				return s.freeram >>= PAGE_SHIFT;
+		}
+	/* XXX support these as well -jj */
+	case SOLARIS_CONFIG_AIO_LISTIO_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_AIO_MAX:		return -EINVAL;
+	case SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_DELAYTIMER_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_MQ_OPEN_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_MQ_PRIO_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_RTSIG_MAX:		return -EINVAL;
+	case SOLARIS_CONFIG_SEM_NSEMS_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_SEM_VALUE_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_SIGQUEUE_MAX:	return -EINVAL;
+	case SOLARIS_CONFIG_TIMER_MAX:		return -EINVAL;
+	default: return -EINVAL;
+	}
+}
+
+asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
+{
+	int ret;
+	
+	switch (cmd) {
+	case 0: /* getpgrp */
+		return process_group(current);
+	case 1: /* setpgrp */
+		{
+			int (*sys_setpgid)(pid_t,pid_t) =
+				(int (*)(pid_t,pid_t))SYS(setpgid);
+				
+			/* can anyone explain me the difference between
+			   Solaris setpgrp and setsid? */
+			ret = sys_setpgid(0, 0);
+			if (ret) return ret;
+			current->signal->tty = NULL;
+			return process_group(current);
+		}
+	case 2: /* getsid */
+		{
+			int (*sys_getsid)(pid_t) = (int (*)(pid_t))SYS(getsid);
+			return sys_getsid(pid);
+		}
+	case 3: /* setsid */
+		{
+			int (*sys_setsid)(void) = (int (*)(void))SYS(setsid);
+			return sys_setsid();
+		}
+	case 4: /* getpgid */
+		{
+			int (*sys_getpgid)(pid_t) = (int (*)(pid_t))SYS(getpgid);
+			return sys_getpgid(pid);
+		}
+	case 5: /* setpgid */
+		{
+			int (*sys_setpgid)(pid_t,pid_t) = 
+				(int (*)(pid_t,pid_t))SYS(setpgid);
+			return sys_setpgid(pid,pgid);
+		}
+	}
+	return -EINVAL;
+}
+
+asmlinkage int solaris_gettimeofday(u32 tim)
+{
+	int (*sys_gettimeofday)(struct timeval *, struct timezone *) =
+		(int (*)(struct timeval *, struct timezone *))SYS(gettimeofday);
+		
+	return sys_gettimeofday((struct timeval *)(u64)tim, NULL);
+}
+
+#define RLIM_SOL_INFINITY32	0x7fffffff
+#define RLIM_SOL_SAVED_MAX32	0x7ffffffe
+#define RLIM_SOL_SAVED_CUR32	0x7ffffffd
+#define RLIM_SOL_INFINITY	((u64)-3)
+#define RLIM_SOL_SAVED_MAX	((u64)-2)
+#define RLIM_SOL_SAVED_CUR	((u64)-1)
+#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+#define RLIMIT_SOL_NOFILE	5
+#define RLIMIT_SOL_VMEM		6
+
+struct rlimit32 {
+	u32	rlim_cur;
+	u32	rlim_max;
+};
+
+asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 __user *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit *) =
+		(int (*)(unsigned int, struct rlimit *))SYS(getrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs (old_fs);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_INFINITY)
+			r.rlim_cur = RLIM_SOL_INFINITY32;
+		else if ((u64)r.rlim_cur > RLIM_SOL_INFINITY32)
+			r.rlim_cur = RLIM_SOL_SAVED_CUR32;
+		if (r.rlim_max == RLIM_INFINITY)
+			r.rlim_max = RLIM_SOL_INFINITY32;
+		else if ((u64)r.rlim_max > RLIM_SOL_INFINITY32)
+			r.rlim_max = RLIM_SOL_SAVED_MAX32;
+		ret = put_user (r.rlim_cur, &rlim->rlim_cur);
+		ret |= __put_user (r.rlim_max, &rlim->rlim_max);
+	}
+	return ret;
+}
+
+asmlinkage int solaris_setrlimit(unsigned int resource, struct rlimit32 __user *rlim)
+{
+	struct rlimit r, rold;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit __user *) =
+		(int (*)(unsigned int, struct rlimit __user *))SYS(getrlimit);
+	int (*sys_setrlimit)(unsigned int, struct rlimit __user *) =
+		(int (*)(unsigned int, struct rlimit __user *))SYS(setrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user (r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &rold);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_SOL_INFINITY32)
+			r.rlim_cur = RLIM_INFINITY;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_CUR32)
+			r.rlim_cur = rold.rlim_cur;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_MAX32)
+			r.rlim_cur = rold.rlim_max;
+		if (r.rlim_max == RLIM_SOL_INFINITY32)
+			r.rlim_max = RLIM_INFINITY;
+		else if (r.rlim_max == RLIM_SOL_SAVED_CUR32)
+			r.rlim_max = rold.rlim_cur;
+		else if (r.rlim_max == RLIM_SOL_SAVED_MAX32)
+			r.rlim_max = rold.rlim_max;
+		ret = sys_setrlimit(resource, &r);
+	}
+	set_fs (old_fs);
+	return ret;
+}
+
+asmlinkage int solaris_getrlimit64(unsigned int resource, struct rlimit __user *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit __user *) =
+		(int (*)(unsigned int, struct rlimit __user *))SYS(getrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
+	set_fs (old_fs);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_INFINITY)
+			r.rlim_cur = RLIM_SOL_INFINITY;
+		if (r.rlim_max == RLIM_INFINITY)
+			r.rlim_max = RLIM_SOL_INFINITY;
+		ret = put_user (r.rlim_cur, &rlim->rlim_cur);
+		ret |= __put_user (r.rlim_max, &rlim->rlim_max);
+	}
+	return ret;
+}
+
+asmlinkage int solaris_setrlimit64(unsigned int resource, struct rlimit __user *rlim)
+{
+	struct rlimit r, rold;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	int (*sys_getrlimit)(unsigned int, struct rlimit __user *) =
+		(int (*)(unsigned int, struct rlimit __user *))SYS(getrlimit);
+	int (*sys_setrlimit)(unsigned int, struct rlimit __user *) =
+		(int (*)(unsigned int, struct rlimit __user *))SYS(setrlimit);
+
+	if (resource > RLIMIT_SOL_VMEM)
+		return -EINVAL;	
+	switch (resource) {
+	case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break;
+	case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break;
+	default: break;
+	}
+	if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+	    __get_user (r.rlim_max, &rlim->rlim_max))
+		return -EFAULT;
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &rold);
+	if (!ret) {
+		if (r.rlim_cur == RLIM_SOL_INFINITY)
+			r.rlim_cur = RLIM_INFINITY;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_CUR)
+			r.rlim_cur = rold.rlim_cur;
+		else if (r.rlim_cur == RLIM_SOL_SAVED_MAX)
+			r.rlim_cur = rold.rlim_max;
+		if (r.rlim_max == RLIM_SOL_INFINITY)
+			r.rlim_max = RLIM_INFINITY;
+		else if (r.rlim_max == RLIM_SOL_SAVED_CUR)
+			r.rlim_max = rold.rlim_cur;
+		else if (r.rlim_max == RLIM_SOL_SAVED_MAX)
+			r.rlim_max = rold.rlim_max;
+		ret = sys_setrlimit(resource, &r);
+	}
+	set_fs (old_fs);
+	return ret;
+}
+
+struct sol_ntptimeval {
+	struct compat_timeval time;
+	s32 maxerror;
+	s32 esterror;
+};
+
+struct sol_timex {
+	u32 modes;
+	s32 offset;
+	s32 freq;
+	s32 maxerror;
+	s32 esterror;
+	s32 status;
+	s32 constant;
+	s32 precision;
+	s32 tolerance;
+	s32 ppsfreq;
+	s32 jitter;
+	s32 shift;
+	s32 stabil;
+	s32 jitcnt;
+	s32 calcnt;
+	s32 errcnt;
+	s32 stbcnt;
+};
+
+asmlinkage int solaris_ntp_gettime(struct sol_ntptimeval __user *ntp)
+{
+	int (*sys_adjtimex)(struct timex __user *) =
+		(int (*)(struct timex __user *))SYS(adjtimex);
+	struct timex t;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	
+	set_fs(KERNEL_DS);
+	t.modes = 0;
+	ret = sys_adjtimex(&t);
+	set_fs(old_fs);
+	if (ret < 0)
+		return ret;
+	ret = put_user (t.time.tv_sec, &ntp->time.tv_sec);
+	ret |= __put_user (t.time.tv_usec, &ntp->time.tv_usec);
+	ret |= __put_user (t.maxerror, &ntp->maxerror);
+	ret |= __put_user (t.esterror, &ntp->esterror);
+	return ret;	                        
+}
+
+asmlinkage int solaris_ntp_adjtime(struct sol_timex __user *txp)
+{
+	int (*sys_adjtimex)(struct timex __user *) =
+		(int (*)(struct timex __user *))SYS(adjtimex);
+	struct timex t;
+	int ret, err;
+	mm_segment_t old_fs = get_fs();
+
+	ret = get_user (t.modes, &txp->modes);
+	ret |= __get_user (t.offset, &txp->offset);
+	ret |= __get_user (t.freq, &txp->freq);
+	ret |= __get_user (t.maxerror, &txp->maxerror);
+	ret |= __get_user (t.esterror, &txp->esterror);
+	ret |= __get_user (t.status, &txp->status);
+	ret |= __get_user (t.constant, &txp->constant);
+	set_fs(KERNEL_DS);
+	ret = sys_adjtimex(&t);
+	set_fs(old_fs);
+	if (ret < 0)
+		return ret;
+	err = put_user (t.offset, &txp->offset);
+	err |= __put_user (t.freq, &txp->freq);
+	err |= __put_user (t.maxerror, &txp->maxerror);
+	err |= __put_user (t.esterror, &txp->esterror);
+	err |= __put_user (t.status, &txp->status);
+	err |= __put_user (t.constant, &txp->constant);
+	err |= __put_user (t.precision, &txp->precision);
+	err |= __put_user (t.tolerance, &txp->tolerance);
+	err |= __put_user (t.ppsfreq, &txp->ppsfreq);
+	err |= __put_user (t.jitter, &txp->jitter);
+	err |= __put_user (t.shift, &txp->shift);
+	err |= __put_user (t.stabil, &txp->stabil);
+	err |= __put_user (t.jitcnt, &txp->jitcnt);
+	err |= __put_user (t.calcnt, &txp->calcnt);
+	err |= __put_user (t.errcnt, &txp->errcnt);
+	err |= __put_user (t.stbcnt, &txp->stbcnt);
+	if (err)
+		return -EFAULT;
+	return ret;
+}
+
+asmlinkage int do_sol_unimplemented(struct pt_regs *regs)
+{
+	printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n", 
+			(int)regs->u_regs[UREG_G1], 
+			(int)regs->u_regs[UREG_I0],
+			(int)regs->u_regs[UREG_I1],
+			(int)regs->u_regs[UREG_I2],
+			(int)regs->u_regs[UREG_I3]);
+	return -ENOSYS;
+}
+
+asmlinkage void solaris_register(void)
+{
+	set_personality(PER_SVR4);
+}
+
+extern long solaris_to_linux_signals[], linux_to_solaris_signals[];
+
+struct exec_domain solaris_exec_domain = {
+	.name =		"Solaris",
+	.handler =	NULL,
+	.pers_low =	1,		/* PER_SVR4 personality */
+	.pers_high =	1,
+	.signal_map =	solaris_to_linux_signals,
+	.signal_invmap =linux_to_solaris_signals,
+	.module =	THIS_MODULE,
+	.next =		NULL
+};
+
+extern int init_socksys(void);
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)");
+MODULE_DESCRIPTION("Solaris binary emulation module");
+MODULE_LICENSE("GPL");
+
+#ifdef __sparc_v9__
+extern u32 tl0_solaris[8];
+#define update_ttable(x) 										\
+	tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000;			\
+	__asm__ __volatile__ ("membar #StoreStore; flush %0" : : "r" (&tl0_solaris[3]))
+#else
+#endif	
+
+extern u32 solaris_sparc_syscall[];
+extern u32 solaris_syscall[];
+extern void cleanup_socksys(void);
+
+extern u32 entry64_personality_patch;
+
+int init_module(void)
+{
+	int ret;
+
+	SOLDD(("Solaris module at %p\n", solaris_sparc_syscall));
+	register_exec_domain(&solaris_exec_domain);
+	if ((ret = init_socksys())) {
+		unregister_exec_domain(&solaris_exec_domain);
+		return ret;
+	}
+	update_ttable(solaris_sparc_syscall);
+	entry64_personality_patch |=
+		(offsetof(struct task_struct, personality) +
+		 (sizeof(unsigned long) - 1));
+	__asm__ __volatile__("membar #StoreStore; flush %0"
+			     : : "r" (&entry64_personality_patch));
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	update_ttable(solaris_syscall);
+	cleanup_socksys();
+	unregister_exec_domain(&solaris_exec_domain);
+}
+
+#else
+int init_solaris_emul(void)
+{
+	register_exec_domain(&solaris_exec_domain);
+	init_socksys();
+	return 0;
+}
+#endif
+
diff --git a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
new file mode 100644
index 0000000..7fa2634
--- /dev/null
+++ b/arch/sparc64/solaris/signal.c
@@ -0,0 +1,430 @@
+/* $Id: signal.c,v 1.7 2000/09/05 21:44:54 davem Exp $
+ * signal.c: Signal emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+
+#include <asm/uaccess.h>
+#include <asm/svr4.h>
+#include <asm/string.h>
+
+#include "conv.h"
+#include "signal.h"
+
+#define _S(nr) (1L<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+long linux_to_solaris_signals[] = {
+        0,
+	SOLARIS_SIGHUP,		SOLARIS_SIGINT,	
+	SOLARIS_SIGQUIT,	SOLARIS_SIGILL,
+	SOLARIS_SIGTRAP,	SOLARIS_SIGIOT,
+	SOLARIS_SIGEMT,		SOLARIS_SIGFPE,
+	SOLARIS_SIGKILL,	SOLARIS_SIGBUS,
+	SOLARIS_SIGSEGV,	SOLARIS_SIGSYS,
+	SOLARIS_SIGPIPE,	SOLARIS_SIGALRM,
+	SOLARIS_SIGTERM,	SOLARIS_SIGURG,
+	SOLARIS_SIGSTOP,	SOLARIS_SIGTSTP,
+	SOLARIS_SIGCONT,	SOLARIS_SIGCLD,
+	SOLARIS_SIGTTIN,	SOLARIS_SIGTTOU,
+	SOLARIS_SIGPOLL,	SOLARIS_SIGXCPU,
+	SOLARIS_SIGXFSZ,	SOLARIS_SIGVTALRM,
+	SOLARIS_SIGPROF,	SOLARIS_SIGWINCH,
+	SOLARIS_SIGUSR1,	SOLARIS_SIGUSR1,
+	SOLARIS_SIGUSR2,	-1,
+};
+
+long solaris_to_linux_signals[] = {
+        0,
+        SIGHUP,		SIGINT,		SIGQUIT,	SIGILL,
+        SIGTRAP,	SIGIOT,		SIGEMT,		SIGFPE,
+        SIGKILL,	SIGBUS,		SIGSEGV,	SIGSYS,
+        SIGPIPE,	SIGALRM,	SIGTERM,	SIGUSR1,
+        SIGUSR2,	SIGCHLD,	-1,		SIGWINCH,
+        SIGURG,		SIGPOLL,	SIGSTOP,	SIGTSTP,
+        SIGCONT,	SIGTTIN,	SIGTTOU,	SIGVTALRM,
+        SIGPROF,	SIGXCPU,	SIGXFSZ,        -1,
+	-1,		-1,		-1,		-1,
+	-1,		-1,		-1,		-1,
+	-1,		-1,		-1,		-1,
+};
+
+static inline long mapsig(long sig)
+{
+	if ((unsigned long)sig > SOLARIS_NSIGNALS)
+		return -EINVAL;
+	return solaris_to_linux_signals[sig];
+}
+
+asmlinkage int solaris_kill(int pid, int sig)
+{
+	int (*sys_kill)(int,int) = 
+		(int (*)(int,int))SYS(kill);
+	int s = mapsig(sig);
+	
+	if (s < 0) return s;
+	return sys_kill(pid, s);
+}
+
+static long sig_handler(int sig, u32 arg, int one_shot)
+{
+	struct sigaction sa, old;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	int (*sys_sigaction)(int,struct sigaction __user *,struct sigaction __user *) = 
+		(int (*)(int,struct sigaction __user *,struct sigaction __user *))SYS(sigaction);
+	
+	sigemptyset(&sa.sa_mask);
+	sa.sa_restorer = NULL;
+	sa.sa_handler = (__sighandler_t)A(arg);
+	sa.sa_flags = 0;
+	if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+	set_fs (KERNEL_DS);
+	ret = sys_sigaction(sig, (void __user *)&sa, (void __user *)&old);
+	set_fs (old_fs);
+	if (ret < 0) return ret;
+	return (u32)(unsigned long)old.sa_handler;
+}
+
+static inline long solaris_signal(int sig, u32 arg)
+{
+	return sig_handler (sig, arg, 1);
+}
+
+static long solaris_sigset(int sig, u32 arg)
+{
+	if (arg != 2) /* HOLD */ {
+		spin_lock_irq(&current->sighand->siglock);
+		sigdelsetmask(&current->blocked, _S(sig));
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+		return sig_handler (sig, arg, 0);
+	} else {
+		spin_lock_irq(&current->sighand->siglock);
+		sigaddsetmask(&current->blocked, (_S(sig) & ~_BLOCKABLE));
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+		return 0;
+	}
+}
+
+static inline long solaris_sighold(int sig)
+{
+	return solaris_sigset(sig, 2);
+}
+
+static inline long solaris_sigrelse(int sig)
+{
+	spin_lock_irq(&current->sighand->siglock);
+	sigdelsetmask(&current->blocked, _S(sig));
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+	return 0;
+}
+
+static inline long solaris_sigignore(int sig)
+{
+	return sig_handler(sig, (u32)(unsigned long)SIG_IGN, 0);
+}
+
+static inline long solaris_sigpause(int sig)
+{
+	printk ("Need to support solaris sigpause\n");
+	return -ENOSYS;
+}
+
+asmlinkage long solaris_sigfunc(int sig, u32 arg)
+{
+	int func = sig & ~0xff;
+	
+	sig = mapsig(sig & 0xff); 
+	if (sig < 0) return sig; 
+	switch (func) {
+	case 0: return solaris_signal(sig, arg); 
+	case 0x100: return solaris_sigset(sig, arg); 
+	case 0x200: return solaris_sighold(sig);
+	case 0x400: return solaris_sigrelse(sig); 
+	case 0x800: return solaris_sigignore(sig); 
+	case 0x1000: return solaris_sigpause(sig);
+	}
+	return -EINVAL;
+}
+
+typedef struct {
+	u32 __sigbits[4];
+} sol_sigset_t;
+
+static inline int mapin(u32 *p, sigset_t *q)
+{
+	int i;
+	u32 x;
+	int sig;
+	
+	sigemptyset(q);
+	x = p[0];
+	for (i = 1; i <= SOLARIS_NSIGNALS; i++) {
+		if (x & 1) {
+			sig = solaris_to_linux_signals[i];
+			if (sig == -1)
+				return -EINVAL;
+			sigaddsetmask(q, (1L << (sig - 1)));
+		}
+		x >>= 1;
+		if (i == 32)
+			x = p[1];
+	}
+	return 0;
+}
+
+static inline int mapout(sigset_t *q, u32 *p)
+{
+	int i;
+	int sig;
+	
+	p[0] = 0;
+	p[1] = 0;
+	for (i = 1; i <= 32; i++) {
+		if (sigismember(q, sigmask(i))) {
+			sig = linux_to_solaris_signals[i];
+			if (sig == -1)
+				return -EINVAL;
+			if (sig > 32)
+				p[1] |= 1L << (sig - 33);
+			else
+				p[0] |= 1L << (sig - 1);
+		}
+	}
+	return 0;
+}
+
+asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out)
+{
+	sigset_t in_s, *ins, out_s, *outs;
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	int (*sys_sigprocmask)(int,sigset_t __user *,sigset_t __user *) = 
+		(int (*)(int,sigset_t __user *,sigset_t __user *))SYS(sigprocmask);
+	
+	ins = NULL; outs = NULL;
+	if (in) {
+		u32 tmp[2];
+		
+		if (copy_from_user (tmp, (void __user *)A(in), 2*sizeof(u32)))
+			return -EFAULT;
+		ins = &in_s;
+		if (mapin (tmp, ins)) return -EINVAL;
+	}
+	if (out) outs = &out_s;
+	set_fs (KERNEL_DS);
+	ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how,
+				(void __user *)ins, (void __user *)outs);
+	set_fs (old_fs);
+	if (ret) return ret;
+	if (out) {
+		u32 tmp[4];
+		
+		tmp[2] = 0; tmp[3] = 0;
+		if (mapout (outs, tmp)) return -EINVAL;
+		if (copy_to_user((void __user *)A(out), tmp, 4*sizeof(u32)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+asmlinkage long do_sol_sigsuspend(u32 mask)
+{
+	sigset_t s;
+	u32 tmp[2];
+		
+	if (copy_from_user (tmp, (sol_sigset_t __user *)A(mask), 2*sizeof(u32)))
+		return -EFAULT;
+	if (mapin (tmp, &s)) return -EINVAL;
+	return (long)s.sig[0];
+}
+
+struct sol_sigaction {
+	int	sa_flags;
+	u32	sa_handler;
+	u32	sa_mask[4];
+	int	sa_resv[2];
+};
+
+asmlinkage int solaris_sigaction(int sig, u32 act, u32 old)
+{
+	u32 tmp, tmp2[4];
+	struct sigaction s, s2;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+	struct sol_sigaction __user *p = (void __user *)A(old);
+	int (*sys_sigaction)(int,struct sigaction __user *,struct sigaction __user *) = 
+		(int (*)(int,struct sigaction __user *,struct sigaction __user *))SYS(sigaction);
+	
+	sig = mapsig(sig); 
+	if (sig < 0) {
+		/* We cheat a little bit for Solaris only signals */
+		if (old && clear_user(p, sizeof(struct sol_sigaction)))
+			return -EFAULT;
+		return 0;
+	}
+	if (act) {
+		if (get_user (tmp, &p->sa_flags))
+			return -EFAULT;
+		s.sa_flags = 0;
+		if (tmp & SOLARIS_SA_ONSTACK) s.sa_flags |= SA_STACK;
+		if (tmp & SOLARIS_SA_RESTART) s.sa_flags |= SA_RESTART;
+		if (tmp & SOLARIS_SA_NODEFER) s.sa_flags |= SA_NOMASK;
+		if (tmp & SOLARIS_SA_RESETHAND) s.sa_flags |= SA_ONESHOT;
+		if (tmp & SOLARIS_SA_NOCLDSTOP) s.sa_flags |= SA_NOCLDSTOP;
+		if (get_user (tmp, &p->sa_handler) ||
+		    copy_from_user (tmp2, &p->sa_mask, 2*sizeof(u32)))
+			return -EFAULT;
+		s.sa_handler = (__sighandler_t)A(tmp);
+		if (mapin (tmp2, &s.sa_mask)) return -EINVAL;
+		s.sa_restorer = NULL;
+	}
+	set_fs(KERNEL_DS);
+	ret = sys_sigaction(sig, act ? (void __user *)&s : NULL,
+				 old ? (void __user *)&s2 : NULL);
+	set_fs(old_fs);
+	if (ret) return ret;
+	if (old) {
+		if (mapout (&s2.sa_mask, tmp2)) return -EINVAL;
+		tmp = 0; tmp2[2] = 0; tmp2[3] = 0;
+		if (s2.sa_flags & SA_STACK) tmp |= SOLARIS_SA_ONSTACK;
+		if (s2.sa_flags & SA_RESTART) tmp |= SOLARIS_SA_RESTART;
+		if (s2.sa_flags & SA_NOMASK) tmp |= SOLARIS_SA_NODEFER;
+		if (s2.sa_flags & SA_ONESHOT) tmp |= SOLARIS_SA_RESETHAND;
+		if (s2.sa_flags & SA_NOCLDSTOP) tmp |= SOLARIS_SA_NOCLDSTOP;
+		if (put_user (tmp, &p->sa_flags) ||
+		    __put_user ((u32)(unsigned long)s2.sa_handler, &p->sa_handler) ||
+		    copy_to_user (&p->sa_mask, tmp2, 4*sizeof(u32)))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+asmlinkage int solaris_sigpending(int which, u32 set)
+{
+	sigset_t s;
+	u32 tmp[4];
+	switch (which) {
+	case 1: /* sigpending */
+		spin_lock_irq(&current->sighand->siglock);
+		sigandsets(&s, &current->blocked, &current->pending.signal);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+		break;
+	case 2: /* sigfillset - I just set signals which have linux equivalents */
+		sigfillset(&s);
+		break;
+	default: return -EINVAL;
+	}
+	if (mapout (&s, tmp)) return -EINVAL;
+	tmp[2] = 0; tmp[3] = 0;
+	if (copy_to_user ((u32 __user *)A(set), tmp, sizeof(tmp)))
+		return -EFAULT;
+	return 0;
+}
+
+asmlinkage int solaris_wait(u32 stat_loc)
+{
+	unsigned __user *p = (unsigned __user *)A(stat_loc);
+	int (*sys_wait4)(pid_t,unsigned __user *, int, struct rusage __user *) =
+		(int (*)(pid_t,unsigned __user *, int, struct rusage __user *))SYS(wait4);
+	int ret, status;
+	
+	ret = sys_wait4(-1, p, WUNTRACED, NULL);
+	if (ret >= 0 && stat_loc) {
+		if (get_user (status, p))
+			return -EFAULT;
+		if (((status - 1) & 0xffff) < 0xff)
+			status = linux_to_solaris_signals[status & 0x7f] & 0x7f;
+		else if ((status & 0xff) == 0x7f)
+			status = (linux_to_solaris_signals[(status >> 8) & 0xff] << 8) | 0x7f;
+		if (__put_user (status, p))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options)
+{
+	int (*sys_wait4)(pid_t,unsigned __user *, int, struct rusage __user *) =
+		(int (*)(pid_t,unsigned __user *, int, struct rusage __user *))SYS(wait4);
+	int opts, status, ret;
+	
+	switch (idtype) {
+	case 0: /* P_PID */ break;
+	case 1: /* P_PGID */ pid = -pid; break;
+	case 7: /* P_ALL */ pid = -1; break;
+	default: return -EINVAL;
+	}
+	opts = 0;
+	if (options & SOLARIS_WUNTRACED) opts |= WUNTRACED;
+	if (options & SOLARIS_WNOHANG) opts |= WNOHANG;
+	current->state = TASK_RUNNING;
+	ret = sys_wait4(pid, (unsigned int __user *)A(info), opts, NULL);
+	if (ret < 0) return ret;
+	if (info) {
+		struct sol_siginfo __user *s = (void __user *)A(info);
+	
+		if (get_user (status, (unsigned int __user *)A(info)))
+			return -EFAULT;
+
+		if (__put_user (SOLARIS_SIGCLD, &s->si_signo) ||
+		    __put_user (ret, &s->_data._proc._pid))
+			return -EFAULT;
+
+		switch (status & 0xff) {
+		case 0: ret = SOLARIS_CLD_EXITED;
+			status = (status >> 8) & 0xff;
+			break;
+		case 0x7f:
+			status = (status >> 8) & 0xff;
+			switch (status) {
+			case SIGSTOP:
+			case SIGTSTP: ret = SOLARIS_CLD_STOPPED;
+			default: ret = SOLARIS_CLD_EXITED;
+			}
+			status = linux_to_solaris_signals[status];
+			break;
+		default:
+			if (status & 0x80) ret = SOLARIS_CLD_DUMPED;
+			else ret = SOLARIS_CLD_KILLED;
+			status = linux_to_solaris_signals[status & 0x7f];
+			break;
+		}
+
+		if (__put_user (ret, &s->si_code) ||
+		    __put_user (status, &s->_data._proc._pdata._cld._status))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs);
+extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs);
+
+asmlinkage int solaris_context(struct pt_regs *regs)
+{
+	switch ((unsigned)regs->u_regs[UREG_I0]) {
+	case 0: /* getcontext */
+		return svr4_getcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
+	case 1: /* setcontext */
+		return svr4_setcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
+	default:
+		return -EINVAL;
+
+	}
+}
+
+asmlinkage int solaris_sigaltstack(u32 ss, u32 oss)
+{
+/* XXX Implement this soon */
+	return 0;
+}
diff --git a/arch/sparc64/solaris/signal.h b/arch/sparc64/solaris/signal.h
new file mode 100644
index 0000000..e915708
--- /dev/null
+++ b/arch/sparc64/solaris/signal.h
@@ -0,0 +1,108 @@
+/* $Id: signal.h,v 1.3 1998/04/12 06:20:33 davem Exp $
+ * signal.h: Signal emulation for Solaris
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+    
+#define SOLARIS_SIGHUP		1
+#define SOLARIS_SIGINT		2
+#define SOLARIS_SIGQUIT		3
+#define SOLARIS_SIGILL		4
+#define SOLARIS_SIGTRAP		5
+#define SOLARIS_SIGIOT		6
+#define SOLARIS_SIGEMT		7
+#define SOLARIS_SIGFPE		8
+#define SOLARIS_SIGKILL		9
+#define SOLARIS_SIGBUS		10
+#define SOLARIS_SIGSEGV		11
+#define SOLARIS_SIGSYS		12
+#define SOLARIS_SIGPIPE		13
+#define SOLARIS_SIGALRM		14
+#define SOLARIS_SIGTERM		15
+#define SOLARIS_SIGUSR1		16
+#define SOLARIS_SIGUSR2		17
+#define SOLARIS_SIGCLD		18
+#define SOLARIS_SIGPWR		19
+#define SOLARIS_SIGWINCH	20
+#define SOLARIS_SIGURG		21
+#define SOLARIS_SIGPOLL		22
+#define SOLARIS_SIGSTOP		23
+#define SOLARIS_SIGTSTP		24
+#define SOLARIS_SIGCONT		25
+#define SOLARIS_SIGTTIN		26
+#define SOLARIS_SIGTTOU		27
+#define SOLARIS_SIGVTALRM	28
+#define SOLARIS_SIGPROF		29
+#define SOLARIS_SIGXCPU		30
+#define SOLARIS_SIGXFSZ		31
+#define SOLARIS_SIGWAITING	32
+#define SOLARIS_SIGLWP		33
+#define SOLARIS_SIGFREEZE	34
+#define SOLARIS_SIGTHAW		35
+#define SOLARIS_SIGCANCEL	36
+#define SOLARIS_SIGRTMIN	37
+#define SOLARIS_SIGRTMAX	44
+#define SOLARIS_NSIGNALS	44
+
+
+#define SOLARIS_SA_ONSTACK	1
+#define SOLARIS_SA_RESETHAND	2
+#define SOLARIS_SA_RESTART	4
+#define SOLARIS_SA_SIGINFO	8
+#define SOLARIS_SA_NODEFER	16
+#define SOLARIS_SA_NOCLDWAIT	0x10000
+#define SOLARIS_SA_NOCLDSTOP	0x20000
+
+struct sol_siginfo {
+	int	si_signo;
+	int	si_code;
+	int	si_errno;
+	union	{
+		char	pad[128-3*sizeof(int)];
+		struct { 
+			s32	_pid;
+			union {
+				struct {
+					s32	_uid;
+					s32	_value;
+				} _kill;
+				struct {
+					s32	_utime;
+					int	_status;
+					s32	_stime;
+				} _cld;
+			} _pdata;
+		} _proc;
+		struct { /* SIGSEGV, SIGBUS, SIGILL and SIGFPE */
+			u32	_addr;
+			int	_trapno;
+		} _fault;
+		struct { /* SIGPOLL, SIGXFSZ */
+			int	_fd;
+			s32	_band;
+		} _file;
+	} _data;
+};
+
+#define SOLARIS_WUNTRACED	0x04
+#define SOLARIS_WNOHANG		0x40
+#define SOLARIS_WEXITED         0x01
+#define SOLARIS_WTRAPPED        0x02
+#define SOLARIS_WSTOPPED        WUNTRACED
+#define SOLARIS_WCONTINUED      0x08
+#define SOLARIS_WNOWAIT         0x80
+
+#define SOLARIS_TRAP_BRKPT      1
+#define SOLARIS_TRAP_TRACE      2
+#define SOLARIS_CLD_EXITED      1
+#define SOLARIS_CLD_KILLED      2
+#define SOLARIS_CLD_DUMPED      3
+#define SOLARIS_CLD_TRAPPED     4
+#define SOLARIS_CLD_STOPPED     5
+#define SOLARIS_CLD_CONTINUED   6
+#define SOLARIS_POLL_IN         1
+#define SOLARIS_POLL_OUT        2
+#define SOLARIS_POLL_MSG        3
+#define SOLARIS_POLL_ERR        4
+#define SOLARIS_POLL_PRI        5
+#define SOLARIS_POLL_HUP        6
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
new file mode 100644
index 0000000..ec8e074
--- /dev/null
+++ b/arch/sparc64/solaris/socket.c
@@ -0,0 +1,415 @@
+/* $Id: socket.c,v 1.6 2002/02/08 03:57:14 davem Exp $
+ * socket.c: Socket syscall emulation for Solaris 2.6+
+ *
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * 1999-08-19 Fixed socketpair code 
+ *            Jason Rappleye (rappleye@ccr.buffalo.edu)
+ */
+
+#include <linux/types.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/socket.h>
+#include <linux/file.h>
+#include <linux/net.h>
+#include <linux/compat.h>
+#include <net/compat.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+
+#include "conv.h"
+
+#define SOCK_SOL_STREAM		2
+#define SOCK_SOL_DGRAM		1
+#define SOCK_SOL_RAW		4
+#define SOCK_SOL_RDM		5
+#define SOCK_SOL_SEQPACKET	6
+
+#define SOL_SO_SNDLOWAT		0x1003
+#define SOL_SO_RCVLOWAT		0x1004
+#define SOL_SO_SNDTIMEO		0x1005
+#define SOL_SO_RCVTIMEO		0x1006
+#define SOL_SO_STATE		0x2000
+
+#define SOL_SS_NDELAY		0x040
+#define SOL_SS_NONBLOCK		0x080
+#define SOL_SS_ASYNC		0x100
+
+#define SO_STATE		0x000e
+
+static int socket_check(int family, int type)
+{
+	if (family != PF_UNIX && family != PF_INET)
+		return -ESOCKTNOSUPPORT;
+	switch (type) {
+	case SOCK_SOL_STREAM: type = SOCK_STREAM; break;
+	case SOCK_SOL_DGRAM: type = SOCK_DGRAM; break;
+	case SOCK_SOL_RAW: type = SOCK_RAW; break;
+	case SOCK_SOL_RDM: type = SOCK_RDM; break;
+	case SOCK_SOL_SEQPACKET: type = SOCK_SEQPACKET; break;
+	default: return -EINVAL;
+	}
+	return type;
+}
+
+static int solaris_to_linux_sockopt(int optname) 
+{
+	switch (optname) {
+	case SOL_SO_SNDLOWAT: optname = SO_SNDLOWAT; break;
+	case SOL_SO_RCVLOWAT: optname = SO_RCVLOWAT; break;
+	case SOL_SO_SNDTIMEO: optname = SO_SNDTIMEO; break;
+	case SOL_SO_RCVTIMEO: optname = SO_RCVTIMEO; break;
+	case SOL_SO_STATE: optname = SO_STATE; break;
+	};
+	
+	return optname;
+}
+	
+asmlinkage int solaris_socket(int family, int type, int protocol)
+{
+	int (*sys_socket)(int, int, int) =
+		(int (*)(int, int, int))SYS(socket);
+
+	type = socket_check (family, type);
+	if (type < 0) return type;
+	return sys_socket(family, type, protocol);
+}
+
+asmlinkage int solaris_socketpair(int *usockvec)
+{
+	int (*sys_socketpair)(int, int, int, int *) =
+		(int (*)(int, int, int, int *))SYS(socketpair);
+
+	/* solaris socketpair really only takes one arg at the syscall
+	 * level, int * usockvec. The libs apparently take care of 
+	 * making sure that family==AF_UNIX and type==SOCK_STREAM. The 
+	 * pointer we really want ends up residing in the first (and
+	 * supposedly only) argument.
+	 */
+
+	return sys_socketpair(AF_UNIX, SOCK_STREAM, 0, (int *)usockvec);
+}
+
+asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen)
+{
+	int (*sys_bind)(int, struct sockaddr *, int) =
+		(int (*)(int, struct sockaddr *, int))SUNOS(104);
+
+	return sys_bind(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
+{
+	int (*sunos_setsockopt)(int, int, int, u32, int) =
+		(int (*)(int, int, int, u32, int))SUNOS(105);
+
+	optname = solaris_to_linux_sockopt(optname);
+	if (optname < 0)
+		return optname;
+	if (optname == SO_STATE)
+		return 0;
+
+	return sunos_setsockopt(fd, level, optname, optval, optlen);
+}
+
+asmlinkage int solaris_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
+{
+	int (*sunos_getsockopt)(int, int, int, u32, u32) =
+		(int (*)(int, int, int, u32, u32))SUNOS(118);
+
+	optname = solaris_to_linux_sockopt(optname);
+	if (optname < 0)
+		return optname;
+
+	if (optname == SO_STATE)
+		optname = SOL_SO_STATE;
+
+	return sunos_getsockopt(fd, level, optname, optval, optlen);
+}
+
+asmlinkage int solaris_connect(int fd, struct sockaddr __user *addr, int addrlen)
+{
+	int (*sys_connect)(int, struct sockaddr __user *, int) =
+		(int (*)(int, struct sockaddr __user *, int))SYS(connect);
+
+	return sys_connect(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_accept(int fd, struct sockaddr __user *addr, int __user *addrlen)
+{
+	int (*sys_accept)(int, struct sockaddr __user *, int __user *) =
+		(int (*)(int, struct sockaddr __user *, int __user *))SYS(accept);
+
+	return sys_accept(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_listen(int fd, int backlog)
+{
+	int (*sys_listen)(int, int) =
+		(int (*)(int, int))SUNOS(106);
+
+	return sys_listen(fd, backlog);
+}
+
+asmlinkage int solaris_shutdown(int fd, int how)
+{
+	int (*sys_shutdown)(int, int) =
+		(int (*)(int, int))SYS(shutdown);
+
+	return sys_shutdown(fd, how);
+}
+
+#define MSG_SOL_OOB		0x1
+#define MSG_SOL_PEEK		0x2
+#define MSG_SOL_DONTROUTE	0x4
+#define MSG_SOL_EOR		0x8
+#define MSG_SOL_CTRUNC		0x10
+#define MSG_SOL_TRUNC		0x20
+#define MSG_SOL_WAITALL		0x40
+#define MSG_SOL_DONTWAIT	0x80
+
+static int solaris_to_linux_msgflags(int flags)
+{
+	int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE);
+	
+	if (flags & MSG_SOL_EOR) fl |= MSG_EOR;
+	if (flags & MSG_SOL_CTRUNC) fl |= MSG_CTRUNC;
+	if (flags & MSG_SOL_TRUNC) fl |= MSG_TRUNC;
+	if (flags & MSG_SOL_WAITALL) fl |= MSG_WAITALL;
+	if (flags & MSG_SOL_DONTWAIT) fl |= MSG_DONTWAIT;
+	return fl;
+}
+
+static int linux_to_solaris_msgflags(int flags)
+{
+	int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE);
+	
+	if (flags & MSG_EOR) fl |= MSG_SOL_EOR;
+	if (flags & MSG_CTRUNC) fl |= MSG_SOL_CTRUNC;
+	if (flags & MSG_TRUNC) fl |= MSG_SOL_TRUNC;
+	if (flags & MSG_WAITALL) fl |= MSG_SOL_WAITALL;
+	if (flags & MSG_DONTWAIT) fl |= MSG_SOL_DONTWAIT;
+	return fl;
+}
+
+asmlinkage int solaris_recvfrom(int s, char __user *buf, int len, int flags, u32 from, u32 fromlen)
+{
+	int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *) =
+		(int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
+	
+	return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), A(from), A(fromlen));
+}
+
+asmlinkage int solaris_recv(int s, char __user *buf, int len, int flags)
+{
+	int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *) =
+		(int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
+	
+	return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL);
+}
+
+asmlinkage int solaris_sendto(int s, char __user *buf, int len, int flags, u32 to, u32 tolen)
+{
+	int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *) =
+		(int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(sendto);
+	
+	return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), A(to), A(tolen));
+}
+
+asmlinkage int solaris_send(int s, char *buf, int len, int flags)
+{
+	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) =
+		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto);
+	
+	return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL);
+}
+
+asmlinkage int solaris_getpeername(int fd, struct sockaddr *addr, int *addrlen)
+{
+	int (*sys_getpeername)(int, struct sockaddr *, int *) =
+		(int (*)(int, struct sockaddr *, int *))SYS(getpeername);
+
+	return sys_getpeername(fd, addr, addrlen);
+}
+
+asmlinkage int solaris_getsockname(int fd, struct sockaddr *addr, int *addrlen)
+{
+	int (*sys_getsockname)(int, struct sockaddr *, int *) =
+		(int (*)(int, struct sockaddr *, int *))SYS(getsockname);
+
+	return sys_getsockname(fd, addr, addrlen);
+}
+
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+					   16 for IP, 16 for IPX,
+					   24 for IPv6,
+					   about 80 for AX.25 */
+
+struct sol_nmsghdr {
+	u32		msg_name;
+	int		msg_namelen;
+	u32		msg_iov;
+	u32		msg_iovlen;
+	u32		msg_control;
+	u32		msg_controllen;
+	u32		msg_flags;
+};
+
+struct sol_cmsghdr {
+	u32		cmsg_len;
+	int		cmsg_level;
+	int		cmsg_type;
+	unsigned char	cmsg_data[0];
+};
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+					     struct sol_nmsghdr __user *umsg)
+{
+	u32 tmp1, tmp2, tmp3;
+	int err;
+
+	err = get_user(tmp1, &umsg->msg_name);
+	err |= __get_user(tmp2, &umsg->msg_iov);
+	err |= __get_user(tmp3, &umsg->msg_control);
+	if (err)
+		return -EFAULT;
+
+	kmsg->msg_name = A(tmp1);
+	kmsg->msg_iov = A(tmp2);
+	kmsg->msg_control = A(tmp3);
+
+	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+	
+	kmsg->msg_flags = solaris_to_linux_msgflags(kmsg->msg_flags);
+	
+	return err;
+}
+
+asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr __user *user_msg, unsigned user_flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];
+	unsigned char *ctl_buf = ctl;
+	struct msghdr kern_msg;
+	int err, total_len;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+	err = verify_compat_iovec(&kern_msg, iov, address, VERIFY_READ);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	if(kern_msg.msg_controllen) {
+		struct sol_cmsghdr __user *ucmsg = kern_msg.msg_control;
+		unsigned long *kcmsg;
+		compat_size_t cmlen;
+
+		if(kern_msg.msg_controllen > sizeof(ctl) &&
+		   kern_msg.msg_controllen <= 256) {
+			err = -ENOBUFS;
+			ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
+			if(!ctl_buf)
+				goto out_freeiov;
+		}
+		__get_user(cmlen, &ucmsg->cmsg_len);
+		kcmsg = (unsigned long *) ctl_buf;
+		*kcmsg++ = (unsigned long)cmlen;
+		err = -EFAULT;
+		if(copy_from_user(kcmsg, &ucmsg->cmsg_level,
+				  kern_msg.msg_controllen - sizeof(compat_size_t)))
+			goto out_freectl;
+		kern_msg.msg_control = ctl_buf;
+	}
+	kern_msg.msg_flags = solaris_to_linux_msgflags(user_flags);
+
+	lock_kernel();
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			kern_msg.msg_flags |= MSG_DONTWAIT;
+		err = sock_sendmsg(sock, &kern_msg, total_len);
+		sockfd_put(sock);
+	}
+	unlock_kernel();
+
+out_freectl:
+	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
+	if(ctl_buf != ctl)
+		kfree(ctl_buf);
+out_freeiov:
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	return err;
+}
+
+asmlinkage int solaris_recvmsg(int fd, struct sol_nmsghdr __user *user_msg, unsigned int user_flags)
+{
+	struct iovec iovstack[UIO_FASTIOV];
+	struct msghdr kern_msg;
+	char addr[MAX_SOCK_ADDR];
+	struct socket *sock;
+	struct iovec *iov = iovstack;
+	struct sockaddr __user *uaddr;
+	int __user *uaddr_len;
+	unsigned long cmsg_ptr;
+	int err, total_len, len = 0;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+
+	uaddr = kern_msg.msg_name;
+	uaddr_len = &user_msg->msg_namelen;
+	err = verify_compat_iovec(&kern_msg, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out;
+	total_len = err;
+
+	cmsg_ptr = (unsigned long) kern_msg.msg_control;
+	kern_msg.msg_flags = 0;
+
+	lock_kernel();
+	sock = sockfd_lookup(fd, &err);
+	if (sock != NULL) {
+		if (sock->file->f_flags & O_NONBLOCK)
+			user_flags |= MSG_DONTWAIT;
+		err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
+		if(err >= 0)
+			len = err;
+		sockfd_put(sock);
+	}
+	unlock_kernel();
+
+	if(uaddr != NULL && err >= 0)
+		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+	if(err >= 0) {
+		err = __put_user(linux_to_solaris_msgflags(kern_msg.msg_flags), &user_msg->msg_flags);
+		if(!err) {
+			/* XXX Convert cmsg back into userspace 32-bit format... */
+			err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr,
+					 &user_msg->msg_controllen);
+		}
+	}
+
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+out:
+	if(err < 0)
+		return err;
+	return len;
+}
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
new file mode 100644
index 0000000..d7c1c76
--- /dev/null
+++ b/arch/sparc64/solaris/socksys.c
@@ -0,0 +1,211 @@
+/* $Id: socksys.c,v 1.21 2002/02/08 03:57:14 davem Exp $
+ * socksys.c: /dev/inet/ stuff for Solaris emulation.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997, 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ */
+
+/*
+ *  Dave, _please_ give me specifications on this fscking mess so that I
+ * could at least get it into the state when it wouldn't screw the rest of
+ * the kernel over.  socksys.c and timod.c _stink_ and we are not talking
+ * H2S here, it's isopropilmercaptan in concentrations way over LD50. -- AV
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/in.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+#include "socksys.h"
+
+static int af_inet_protocols[] = {
+IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP,
+IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
+0, 0, 0, 0, 0, 0,
+};
+
+#ifndef DEBUG_SOLARIS_KMALLOC
+
+#define mykmalloc kmalloc
+#define mykfree kfree
+
+#else
+
+extern void * mykmalloc(size_t s, int gfp);
+extern void mykfree(void *);
+
+#endif
+
+static unsigned int (*sock_poll)(struct file *, poll_table *);
+
+static struct file_operations socksys_file_ops = {
+	/* Currently empty */
+};
+
+static int socksys_open(struct inode * inode, struct file * filp)
+{
+	int family, type, protocol, fd;
+	struct dentry *dentry;
+	int (*sys_socket)(int,int,int) =
+		(int (*)(int,int,int))SUNOS(97);
+        struct sol_socket_struct * sock;
+	
+	family = ((iminor(inode) >> 4) & 0xf);
+	switch (family) {
+	case AF_UNIX:
+		type = SOCK_STREAM;
+		protocol = 0;
+		break;
+	case AF_INET:
+		protocol = af_inet_protocols[iminor(inode) & 0xf];
+		switch (protocol) {
+		case IPPROTO_TCP: type = SOCK_STREAM; break;
+		case IPPROTO_UDP: type = SOCK_DGRAM; break;
+		default: type = SOCK_RAW; break;
+		}
+		break;
+	default:
+		type = SOCK_RAW;
+		protocol = 0;
+		break;
+	}
+
+	fd = sys_socket(family, type, protocol);
+	if (fd < 0)
+		return fd;
+	/*
+	 * N.B. The following operations are not legal!
+	 *
+	 * No shit.  WTF is it supposed to do, anyway?
+	 *
+	 * Try instead:
+	 * d_delete(filp->f_dentry), then d_instantiate with sock inode
+	 */
+	dentry = filp->f_dentry;
+	filp->f_dentry = dget(fcheck(fd)->f_dentry);
+	filp->f_dentry->d_inode->i_rdev = inode->i_rdev;
+	filp->f_dentry->d_inode->i_flock = inode->i_flock;
+	SOCKET_I(filp->f_dentry->d_inode)->file = filp;
+	filp->f_op = &socksys_file_ops;
+        sock = (struct sol_socket_struct*) 
+        	mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
+        if (!sock) return -ENOMEM;
+	SOLDD(("sock=%016lx(%016lx)\n", sock, filp));
+        sock->magic = SOLARIS_SOCKET_MAGIC;
+        sock->modcount = 0;
+        sock->state = TS_UNBND;
+        sock->offset = 0;
+        sock->pfirst = sock->plast = NULL;
+        filp->private_data = sock;
+	SOLDD(("filp->private_data %016lx\n", filp->private_data));
+
+	sys_close(fd);
+	dput(dentry);
+	return 0;
+}
+
+static int socksys_release(struct inode * inode, struct file * filp)
+{
+        struct sol_socket_struct * sock;
+        struct T_primsg *it;
+
+	/* XXX: check this */
+	sock = (struct sol_socket_struct *)filp->private_data;
+	SOLDD(("sock release %016lx(%016lx)\n", sock, filp));
+	it = sock->pfirst;
+	while (it) {
+		struct T_primsg *next = it->next;
+		
+		SOLDD(("socksys_release %016lx->%016lx\n", it, next));
+		mykfree((char*)it);
+		it = next;
+	}
+	filp->private_data = NULL;
+	SOLDD(("socksys_release %016lx\n", sock));
+	mykfree((char*)sock);
+	return 0;
+}
+
+static unsigned int socksys_poll(struct file * filp, poll_table * wait)
+{
+	struct inode *ino;
+	unsigned int mask = 0;
+
+	ino=filp->f_dentry->d_inode;
+	if (ino && S_ISSOCK(ino->i_mode)) {
+		struct sol_socket_struct *sock;
+		sock = (struct sol_socket_struct*)filp->private_data;
+		if (sock && sock->pfirst) {
+			mask |= POLLIN | POLLRDNORM;
+			if (sock->pfirst->pri == MSG_HIPRI)
+				mask |= POLLPRI;
+		}
+	}
+	if (sock_poll)
+		mask |= (*sock_poll)(filp, wait);
+	return mask;
+}
+	
+static struct file_operations socksys_fops = {
+	.open =		socksys_open,
+	.release =	socksys_release,
+};
+
+int __init
+init_socksys(void)
+{
+	int ret;
+	struct file * file;
+	int (*sys_socket)(int,int,int) =
+		(int (*)(int,int,int))SUNOS(97);
+	int (*sys_close)(unsigned int) = 
+		(int (*)(unsigned int))SYS(close);
+	
+	ret = register_chrdev (30, "socksys", &socksys_fops);
+	if (ret < 0) {
+		printk ("Couldn't register socksys character device\n");
+		return ret;
+	}
+	ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (ret < 0) {
+		printk ("Couldn't create socket\n");
+		return ret;
+	}
+
+	devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUSR|S_IWUSR, "socksys");
+
+	file = fcheck(ret);
+	/* N.B. Is this valid? Suppose the f_ops are in a module ... */
+	socksys_file_ops = *file->f_op;
+	sys_close(ret);
+	sock_poll = socksys_file_ops.poll;
+	socksys_file_ops.poll = socksys_poll;
+	socksys_file_ops.release = socksys_release;
+	return 0;
+}
+
+void
+cleanup_socksys(void)
+{
+	if (unregister_chrdev(30, "socksys"))
+		printk ("Couldn't unregister socksys character device\n");
+	devfs_remove ("socksys");
+}
diff --git a/arch/sparc64/solaris/socksys.h b/arch/sparc64/solaris/socksys.h
new file mode 100644
index 0000000..5d1b78e
--- /dev/null
+++ b/arch/sparc64/solaris/socksys.h
@@ -0,0 +1,208 @@
+/* $Id: socksys.h,v 1.2 1998/03/26 08:46:07 jj Exp $
+ * socksys.h: Definitions for STREAMS modules emulation code.
+ *
+ * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ */
+
+#define MSG_HIPRI	0x01
+#define MSG_ANY		0x02
+#define MSG_BAND	0x04
+
+#define MORECTL		1
+#define MOREDATA	2
+
+#define	TBADADDR		1
+#define	TBADOPT			2
+#define	TACCES			3
+#define TBADF			4
+#define TNOADDR			5
+#define TOUTSTATE	        6
+#define TBADSEQ		        7
+#define TSYSERR			8
+#define TLOOK		        9
+#define TBADDATA	       10
+#define TBUFOVFLW	       11
+#define TFLOW		       12
+#define	TNODATA		       13
+#define TNODIS		       14
+#define TNOUDERR	       15
+#define TBADFLAG	       16
+#define TNOREL		       17
+#define TNOTSUPPORT	       18
+#define TSTATECHNG	       19
+
+#define T_CONN_REQ      0
+#define T_CONN_RES      1
+#define T_DISCON_REQ    2
+#define T_DATA_REQ      3
+#define T_EXDATA_REQ    4
+#define T_INFO_REQ      5
+#define T_BIND_REQ      6
+#define T_UNBIND_REQ    7
+#define T_UNITDATA_REQ  8
+#define T_OPTMGMT_REQ   9
+#define T_ORDREL_REQ    10
+
+#define T_CONN_IND      11
+#define T_CONN_CON      12
+#define T_DISCON_IND    13
+#define T_DATA_IND      14
+#define T_EXDATA_IND    15
+#define T_INFO_ACK      16
+#define T_BIND_ACK      17
+#define T_ERROR_ACK     18
+#define T_OK_ACK        19
+#define T_UNITDATA_IND  20
+#define T_UDERROR_IND   21
+#define T_OPTMGMT_ACK   22
+#define T_ORDREL_IND    23
+
+#define T_NEGOTIATE	0x0004
+#define T_FAILURE	0x0040
+
+#define TS_UNBND	0	/* unbound */
+#define	TS_WACK_BREQ	1	/* waiting for T_BIND_REQ ack  */
+#define TS_WACK_UREQ	2	/* waiting for T_UNBIND_REQ ack */
+#define TS_IDLE		3	/* idle */
+#define TS_WACK_OPTREQ	4	/* waiting for T_OPTMGMT_REQ ack */
+#define TS_WACK_CREQ	5	/* waiting for T_CONN_REQ ack */
+#define TS_WCON_CREQ	6	/* waiting for T_CONN_REQ confirmation */
+#define	TS_WRES_CIND	7	/* waiting for T_CONN_IND */
+#define TS_WACK_CRES	8	/* waiting for T_CONN_RES ack */
+#define TS_DATA_XFER	9	/* data transfer */
+#define TS_WIND_ORDREL	10	/* releasing read but not write */
+#define TS_WREQ_ORDREL	11      /* wait to release write but not read */
+#define TS_WACK_DREQ6	12	/* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ7	13	/* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ9	14	/* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ10	15	/* waiting for T_DISCON_REQ ack */
+#define TS_WACK_DREQ11	16	/* waiting for T_DISCON_REQ ack */
+#define TS_NOSTATES	17
+
+struct T_conn_req {
+	s32 PRIM_type; 
+	s32 DEST_length;
+	s32 DEST_offset;
+	s32 OPT_length;
+	s32 OPT_offset;
+};
+
+struct T_bind_req {
+	s32 PRIM_type;
+	s32 ADDR_length;
+	s32 ADDR_offset;
+	u32 CONIND_number;
+};
+
+struct T_unitdata_req {
+	s32 PRIM_type; 
+	s32 DEST_length;
+	s32 DEST_offset;
+	s32 OPT_length;
+	s32 OPT_offset;
+};
+
+struct T_optmgmt_req {
+	s32 PRIM_type; 
+	s32 OPT_length;
+	s32 OPT_offset;
+	s32 MGMT_flags;
+};
+
+struct T_bind_ack {
+	s32 PRIM_type;
+	s32 ADDR_length;
+	s32 ADDR_offset;
+	u32 CONIND_number;
+};
+
+struct T_error_ack {
+	s32 PRIM_type;
+	s32 ERROR_prim;
+	s32 TLI_error;
+	s32 UNIX_error;
+};
+
+struct T_ok_ack {
+	s32 PRIM_type;
+	s32 CORRECT_prim;
+};
+
+struct T_conn_ind {
+	s32 PRIM_type;
+	s32 SRC_length;
+	s32 SRC_offset;
+	s32 OPT_length;
+	s32 OPT_offset;
+	s32 SEQ_number;
+};
+
+struct T_conn_con {
+	s32 PRIM_type;
+	s32 RES_length;
+	s32 RES_offset;
+	s32 OPT_length;
+	s32 OPT_offset;
+};
+
+struct T_discon_ind {
+	s32 PRIM_type;
+	s32 DISCON_reason;
+	s32 SEQ_number;
+};
+
+struct T_unitdata_ind {
+	s32 PRIM_type;
+	s32 SRC_length;
+	s32 SRC_offset;
+	s32 OPT_length;
+	s32 OPT_offset;
+};
+
+struct T_optmgmt_ack {
+	s32 PRIM_type; 
+	s32 OPT_length;
+	s32 OPT_offset;
+	s32 MGMT_flags;
+};
+
+struct opthdr {
+	s32 level;
+	s32 name;
+	s32 len;
+	char value[0];	
+};
+
+struct T_primsg {
+	struct T_primsg *next;
+	unsigned char pri;
+	unsigned char band;
+	int length;
+	s32 type;
+};
+
+struct strbuf {
+	s32 maxlen;
+	s32 len;
+	u32 buf;
+} ;
+
+/* Constants used by STREAMS modules emulation code */
+
+typedef char sol_module;
+
+#define MAX_NR_STREAM_MODULES   16
+
+/* Private data structure assigned to sockets. */
+
+struct sol_socket_struct {
+        int magic;
+        int modcount;
+        sol_module module[MAX_NR_STREAM_MODULES];
+        long state;
+        int offset;
+        struct T_primsg *pfirst, *plast;
+};
+
+#define SOLARIS_SOCKET_MAGIC    0xADDED
+
diff --git a/arch/sparc64/solaris/systbl.S b/arch/sparc64/solaris/systbl.S
new file mode 100644
index 0000000..d25667e
--- /dev/null
+++ b/arch/sparc64/solaris/systbl.S
@@ -0,0 +1,314 @@
+/* $Id: systbl.S,v 1.11 2000/03/13 21:57:35 davem Exp $
+ * systbl.S: System call entry point table for Solaris compatibility.
+ *
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <asm/unistd.h>
+
+/* Fall back to sys_call_table32 entry */
+#define CHAIN(name)	__NR_##name
+
+/* Pass pt_regs pointer as first argument */
+#define REGS(name)	name+1
+
+/* Hack till all be implemented */
+#define solaris_getpmsg		solaris_unimplemented
+#define solaris_hrtsys		solaris_unimplemented
+#define solaris_msgsys		solaris_unimplemented
+#define solaris_putpmsg		solaris_unimplemented
+#define solaris_semsys		solaris_unimplemented
+
+        .data
+	.globl		solaris_sys_table
+solaris_sys_table:
+	.word solaris_unimplemented	/* nosys		0	*/
+	.word CHAIN(exit)		/* exit		d	1	*/
+	.word CHAIN(fork)		/* fork			2	*/
+	.word CHAIN(read)		/* read		dpd	3	*/
+	.word CHAIN(write)		/* write	dpd	4	*/
+	.word solaris_open		/* open		soo	5	*/
+	.word CHAIN(close)		/* close	d	6	*/
+	.word solaris_wait		/* wait		xxx	7	*/
+	.word CHAIN(creat)		/* creat	so	8	*/
+	.word CHAIN(link)		/* link		ss	9	*/
+	.word CHAIN(unlink)		/* unlink	s	10	*/
+	.word solaris_unimplemented	/* exec		sxx	11	*/
+	.word CHAIN(chdir)		/* chdir	s	12	*/
+	.word CHAIN(time)		/* time			13	*/
+	.word solaris_mknod		/* mknod	sox	14	*/
+	.word CHAIN(chmod)		/* chmod	so	15	*/ 
+	.word CHAIN(chown)		/* chown	sdd	16	*/
+	.word solaris_brk		/* brk/break	x	17	*/
+	.word solaris_stat		/* stat		sp	18	*/
+	.word CHAIN(lseek)		/* seek/lseek	ddd	19	*/
+	.word solaris_getpid		/* getpid		20	*/
+	.word solaris_unimplemented	/* mount		21	*/
+	.word CHAIN(umount)		/* umount	s	22	*/
+	.word CHAIN(setuid)		/* setuid	d	23	*/
+	.word solaris_getuid		/* getuid		24	*/
+	.word CHAIN(stime)		/* stime	d	25	*/
+#if 0
+	.word solaris_ptrace		/* ptrace	xdxx	26	*/
+#else
+	.word CHAIN(ptrace)		/* ptrace	xdxx	26	*/
+#endif
+	.word CHAIN(alarm)		/* alarm	d	27	*/
+	.word solaris_fstat		/* fstat	dp	28	*/
+	.word CHAIN(pause)		/* pause		29	*/
+	.word CHAIN(utime)		/* utime	xx	30	*/
+	.word solaris_unimplemented	/* stty			31	*/
+	.word solaris_unimplemented	/* gtty			32	*/
+	.word solaris_access		/* access	so	33	*/
+	.word CHAIN(nice)		/* nice		d	34	*/
+	.word solaris_statfs		/* statfs	spdd	35	*/
+	.word CHAIN(sync)		/* sync			36	*/
+	.word solaris_kill		/* kill		dd	37	*/
+	.word solaris_fstatfs		/* fstatfs	dpdd	38	*/
+	.word solaris_procids		/* pgrpsys	ddd	39	*/
+	.word solaris_unimplemented	/* xenix		40	*/
+	.word CHAIN(dup)		/* dup		d	41	*/
+	.word CHAIN(pipe)		/* pipe			42	*/
+	.word CHAIN(times)		/* times	p	43	*/
+	.word 44 /*CHAIN(profil)*/	/* prof		xxxx	44	*/
+	.word solaris_unimplemented	/* lock/plock		45	*/
+	.word CHAIN(setgid)		/* setgid	d	46	*/
+	.word solaris_getgid		/* getgid		47	*/
+	.word solaris_sigfunc		/* sigfunc	xx	48	*/
+	.word REGS(solaris_msgsys)	/* msgsys	dxddd	49	*/
+	.word solaris_unimplemented	/* syssun/3b		50	*/
+	.word CHAIN(acct)		/* acct/sysacct	x	51	*/
+	.word solaris_shmsys		/* shmsys	ddxo	52	*/
+	.word REGS(solaris_semsys)	/* semsys	dddx	53	*/
+	.word solaris_ioctl		/* ioctl	dxx	54	*/
+	.word solaris_unimplemented	/* uadmin	xxx	55	*/
+	.word solaris_unimplemented	/* reserved:exch	56	*/
+	.word solaris_utssys		/* utssys	x	57	*/
+	.word CHAIN(fsync)		/* fsync	d	58	*/
+	.word CHAIN(execve)		/* execv	spp	59	*/
+	.word CHAIN(umask)		/* umask	o	60	*/
+	.word CHAIN(chroot)		/* chroot	s	61	*/
+	.word solaris_fcntl		/* fcntl	dxx	62	*/
+	.word solaris_ulimit		/* ulimit	xx	63	*/
+	.word solaris_unimplemented	/* ?			64	*/
+	.word solaris_unimplemented	/* ?			65	*/
+	.word solaris_unimplemented	/* ?			66	*/
+	.word solaris_unimplemented	/* ?			67	*/
+	.word solaris_unimplemented	/* ?			68	*/
+	.word solaris_unimplemented	/* ?			69	*/
+	.word solaris_unimplemented	/* advfs		70	*/
+	.word solaris_unimplemented	/* unadvfs		71	*/
+	.word solaris_unimplemented	/* rmount		72	*/
+	.word solaris_unimplemented	/* rumount		73	*/
+	.word solaris_unimplemented	/* rfstart		74	*/
+	.word solaris_unimplemented	/* ?			75	*/
+	.word solaris_unimplemented	/* rdebug		76	*/
+	.word solaris_unimplemented	/* rfstop		77	*/
+	.word solaris_unimplemented	/* rfsys		78	*/
+	.word CHAIN(rmdir)		/* rmdir	s	79	*/
+	.word CHAIN(mkdir)		/* mkdir	so	80	*/
+	.word CHAIN(getdents)		/* getdents	dxd	81	*/
+	.word solaris_unimplemented	/* libattach		82	*/
+	.word solaris_unimplemented	/* libdetach		83	*/
+	.word CHAIN(sysfs)		/* sysfs	dxx	84	*/
+	.word solaris_getmsg		/* getmsg	dxxx	85	*/
+	.word solaris_putmsg		/* putmsg	dxxd	86	*/
+	.word CHAIN(poll)		/* poll		xdd	87	*/
+	.word solaris_lstat		/* lstat	sp	88	*/
+	.word CHAIN(symlink)		/* symlink	ss	89	*/
+	.word CHAIN(readlink)		/* readlink	spd	90	*/
+	.word CHAIN(setgroups)		/* setgroups	dp	91	*/
+	.word CHAIN(getgroups)		/* getgroups	dp	92	*/
+	.word CHAIN(fchmod)		/* fchmod	do	93	*/
+	.word CHAIN(fchown)		/* fchown	ddd	94	*/
+	.word solaris_sigprocmask	/* sigprocmask	dxx	95	*/
+	.word solaris_sigsuspend	/* sigsuspend	x	96	*/
+	.word solaris_sigaltstack	/* sigaltstack	xx	97	*/
+	.word solaris_sigaction		/* sigaction	dxx	98	*/
+	.word solaris_sigpending	/* sigpending	dd	99	*/
+	.word REGS(solaris_context)	/* context		100	*/
+	.word solaris_unimplemented	/* evsys		101	*/
+	.word solaris_unimplemented	/* evtrapret		102	*/
+	.word solaris_statvfs		/* statvfs	sp	103	*/
+	.word solaris_fstatvfs		/* fstatvfs	dp	104	*/
+	.word solaris_unimplemented	/* unknown		105	*/
+	.word solaris_unimplemented	/* nfssys		106	*/
+	.word solaris_waitid		/* waitid	ddxd	107	*/
+	.word solaris_unimplemented	/* sigsendsys	ddd	108	*/
+	.word REGS(solaris_hrtsys)	/* hrtsys	xxx	109	*/
+	.word solaris_unimplemented	/* acancel	dxd	110	*/
+	.word solaris_unimplemented	/* async		111	*/
+	.word solaris_unimplemented	/* priocntlsys		112	*/
+	.word solaris_pathconf		/* pathconf	sd	113	*/
+	.word CHAIN(mincore)		/* mincore	d	114	*/
+	.word solaris_mmap		/* mmap		xxxxdx	115	*/
+	.word CHAIN(mprotect)		/* mprotect	xdx	116	*/
+	.word CHAIN(munmap)		/* munmap	xd	117	*/
+	.word solaris_fpathconf		/* fpathconf	dd	118	*/
+	.word CHAIN(fork)		/* fork			119	*/
+	.word solaris_unimplemented	/* fchdir	d	120	*/
+	.word CHAIN(readv)		/* readv	dxd	121	*/
+	.word CHAIN(writev)		/* writev	dxd	122	*/
+	.word solaris_xstat		/* xstat	dsx	123	*/
+	.word solaris_lxstat		/* lxstat	dsx	124	*/
+	.word solaris_fxstat		/* fxstat	ddx	125	*/
+	.word solaris_xmknod		/* xmknod	dsox	126	*/
+	.word solaris_unimplemented	/* syslocal	d	127	*/
+	.word solaris_setrlimit		/* setrlimit	dp	128	*/
+	.word solaris_getrlimit		/* getrlimit	dp	129	*/
+	.word CHAIN(chown)		/* lchown	sdd	130	*/
+	.word solaris_unimplemented	/* memcntl		131	*/
+	.word solaris_getpmsg		/* getpmsg	dxxxx	132	*/
+	.word solaris_putpmsg		/* putpmsg	dxxdd	133	*/
+	.word CHAIN(rename)		/* rename	ss	134	*/
+	.word solaris_utsname		/* uname	x	135	*/
+	.word solaris_unimplemented	/* setegid		136	*/
+	.word solaris_sysconf		/* sysconfig	d	137	*/
+	.word solaris_unimplemented	/* adjtime		138	*/
+	.word solaris_sysinfo		/* systeminfo	dsd	139	*/
+	.word solaris_unimplemented	/* ?			140	*/
+	.word solaris_unimplemented	/* seteuid		141	*/
+	.word solaris_unimplemented	/* ?			142	*/
+	.word solaris_unimplemented	/* ?			143	*/
+	.word solaris_unimplemented	/* secsys	dx	144	*/
+	.word solaris_unimplemented	/* filepriv	sdxd	145	*/
+	.word solaris_unimplemented	/* procpriv	dxd	146	*/
+	.word solaris_unimplemented	/* devstat	sdx	147	*/
+	.word solaris_unimplemented	/* aclipc	ddddx	148	*/
+	.word solaris_unimplemented	/* fdevstat	ddx	149	*/
+	.word solaris_unimplemented	/* flvlfile	ddx	150	*/
+	.word solaris_unimplemented	/* lvlfile	sdx	151	*/
+	.word solaris_unimplemented	/* ?			152	*/
+	.word solaris_unimplemented	/* fchroot	d	153	*/
+	.word solaris_unimplemented	/* lvlproc	dx	154	*/
+	.word solaris_unimplemented	/* ?			155	*/
+	.word solaris_gettimeofday	/* gettimeofday	x	156	*/
+	.word CHAIN(getitimer)		/* getitimer	dx	157	*/
+	.word CHAIN(setitimer)		/* setitimer	dxx	158	*/
+	.word solaris_unimplemented	/* lwp-xxx		159	*/
+	.word solaris_unimplemented	/* lwp-xxx		160	*/
+	.word solaris_unimplemented	/* lwp-xxx		161	*/
+	.word solaris_unimplemented	/* lwp-xxx		162	*/
+	.word solaris_unimplemented	/* lwp-xxx		163	*/
+	.word solaris_unimplemented	/* lwp-xxx		164	*/
+	.word solaris_unimplemented	/* lwp-xxx		165	*/
+	.word solaris_unimplemented	/* lwp-xxx		166	*/
+	.word solaris_unimplemented	/* lwp-xxx		167	*/
+	.word solaris_unimplemented	/* lwp-xxx		168	*/
+	.word solaris_unimplemented	/* lwp-xxx		169	*/
+	.word solaris_unimplemented	/* lwp-xxx		170	*/
+	.word solaris_unimplemented	/* lwp-xxx		171	*/
+	.word solaris_unimplemented	/* lwp-xxx		172	*/
+	.word solaris_pread		/* pread	dpdd	173	*/
+	.word solaris_pwrite		/* pwrite	dpdd	174	*/
+	.word REGS(solaris_llseek)	/* llseek	dLd	175	*/
+	.word solaris_unimplemented	/* lwpself		176	*/
+	.word solaris_unimplemented	/* lwpinfo		177	*/
+	.word solaris_unimplemented	/* lwpprivate		178	*/
+	.word solaris_unimplemented	/* processorbind	179	*/
+	.word solaris_unimplemented	/* processorexbind	180	*/
+	.word solaris_unimplemented	/* 			181	*/
+	.word solaris_unimplemented	/* sync_mailbox		182	*/
+	.word solaris_unimplemented	/* prepblock		183	*/
+	.word solaris_unimplemented	/* block		184	*/
+	.word solaris_acl		/* acl		sddp	185	*/
+	.word solaris_unimplemented	/* unblock		186	*/
+	.word solaris_unimplemented	/* cancelblock		187	*/
+	.word solaris_unimplemented	/* ?			188	*/
+	.word solaris_unimplemented	/* xxxxx		189	*/
+	.word solaris_unimplemented	/* xxxxxe		190	*/
+	.word solaris_unimplemented	/*			191	*/
+	.word solaris_unimplemented	/*			192	*/
+	.word solaris_unimplemented	/*			193	*/
+	.word solaris_unimplemented	/*			194	*/
+	.word solaris_unimplemented	/* 			195	*/
+	.word solaris_unimplemented	/* 			196	*/
+	.word solaris_unimplemented	/* 			197	*/
+	.word solaris_unimplemented	/* 			198	*/
+	.word CHAIN(nanosleep)		/* nanosleep	dd	199	*/
+	.word solaris_facl		/* facl		dddp	200	*/
+	.word solaris_unimplemented	/* 			201	*/
+	.word CHAIN(setreuid)		/* setreuid	dd	202	*/
+	.word CHAIN(setregid)		/* setregid	dd	203	*/
+	.word solaris_unimplemented	/* 			204	*/
+	.word solaris_unimplemented	/* 			205	*/
+	.word solaris_unimplemented	/* 			206	*/
+	.word solaris_unimplemented	/* 			207	*/
+	.word solaris_unimplemented	/* 			208	*/
+	.word solaris_unimplemented	/* 			209	*/
+	.word solaris_unimplemented	/* 			210	*/
+	.word solaris_unimplemented	/* 			211	*/
+	.word solaris_unimplemented	/* 			212	*/
+	.word solaris_getdents64	/* getdents64	dpd	213	*/
+	.word REGS(solaris_mmap64)	/* mmap64	xxxxdX	214	*/
+	.word solaris_stat64		/* stat64	sP	215	*/
+	.word solaris_lstat64		/* lstat64	sP	216	*/
+	.word solaris_fstat64		/* fstat64	dP	217	*/
+	.word solaris_statvfs64		/* statvfs64	sP	218	*/
+	.word solaris_fstatvfs64	/* fstatvfs64	dP	219	*/
+	.word solaris_setrlimit64	/* setrlimit64	dP	220	*/
+	.word solaris_getrlimit64	/* getrlimit64	dP	221	*/
+	.word CHAIN(pread64)		/* pread64	dpdD	222	*/
+	.word CHAIN(pwrite64)		/* pwrite64	dpdD	223	*/
+	.word CHAIN(creat)		/* creat64	so	224	*/
+	.word solaris_open		/* open64	soo	225	*/
+	.word solaris_unimplemented	/* 			226	*/
+	.word solaris_unimplemented	/* 			227	*/
+	.word solaris_unimplemented	/* 			228	*/
+	.word solaris_unimplemented	/* 			229	*/
+	.word solaris_socket		/* socket	ddd	230	*/
+	.word solaris_socketpair	/* socketpair	dddp	231	*/
+	.word solaris_bind		/* bind		dpd	232	*/
+	.word solaris_listen		/* listen	dd	233	*/
+	.word solaris_accept		/* accept	dpp	234	*/
+	.word solaris_connect		/* connect	dpd	235	*/
+	.word solaris_shutdown		/* shutdown	dd	236	*/
+	.word solaris_recv		/* recv		dpdd	237	*/
+	.word solaris_recvfrom		/* recvfrom	dpddpp	238	*/
+	.word solaris_recvmsg		/* recvmsg	dpd	239	*/
+	.word solaris_send		/* send		dpdd	240	*/
+	.word solaris_sendmsg		/* sendmsg	dpd	241	*/
+	.word solaris_sendto		/* sendto	dpddpd	242	*/
+	.word solaris_getpeername	/* getpeername	dpp	243	*/
+	.word solaris_getsockname	/* getsockname	dpp	244	*/
+	.word solaris_getsockopt	/* getsockopt	dddpp	245	*/
+	.word solaris_setsockopt	/* setsockopt	dddpp	246	*/
+	.word solaris_unimplemented	/* 			247	*/
+	.word solaris_ntp_gettime	/* ntp_gettime	p	248	*/
+	.word solaris_ntp_adjtime	/* ntp_adjtime	p	249	*/
+	.word solaris_unimplemented	/* 			250	*/
+	.word solaris_unimplemented	/* 			251	*/
+	.word solaris_unimplemented	/* 			252	*/
+	.word solaris_unimplemented	/* 			253	*/
+	.word solaris_unimplemented	/* 			254	*/
+	.word solaris_unimplemented	/* 			255	*/
+	.word solaris_unimplemented	/* 			256	*/
+	.word solaris_unimplemented	/* 			257	*/
+	.word solaris_unimplemented	/* 			258	*/
+	.word solaris_unimplemented	/* 			259	*/
+	.word solaris_unimplemented	/* 			260	*/
+	.word solaris_unimplemented	/* 			261	*/
+	.word solaris_unimplemented	/* 			262	*/
+	.word solaris_unimplemented	/* 			263	*/
+	.word solaris_unimplemented	/* 			264	*/
+	.word solaris_unimplemented	/* 			265	*/
+	.word solaris_unimplemented	/* 			266	*/
+	.word solaris_unimplemented	/* 			267	*/
+	.word solaris_unimplemented	/* 			268	*/
+	.word solaris_unimplemented	/* 			269	*/
+	.word solaris_unimplemented	/* 			270	*/
+	.word solaris_unimplemented	/* 			271	*/
+	.word solaris_unimplemented	/* 			272	*/
+	.word solaris_unimplemented	/* 			273	*/
+	.word solaris_unimplemented	/* 			274	*/
+	.word solaris_unimplemented	/* 			275	*/
+	.word solaris_unimplemented	/* 			276	*/
+	.word solaris_unimplemented	/* 			277	*/
+	.word solaris_unimplemented	/* 			278	*/
+	.word solaris_unimplemented	/* 			279	*/
+	.word solaris_unimplemented	/* 			280	*/
+	.word solaris_unimplemented	/* 			281	*/
+	.word solaris_unimplemented	/* 			282	*/
+	.word solaris_unimplemented	/* 			283	*/
+
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
new file mode 100644
index 0000000..022c80f
--- /dev/null
+++ b/arch/sparc64/solaris/timod.c
@@ -0,0 +1,959 @@
+/* $Id: timod.c,v 1.19 2002/02/08 03:57:14 davem Exp $
+ * timod.c: timod emulation.
+ *
+ * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ *
+ * Streams & timod emulation based on code
+ * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
+ *
+ */
+ 
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+#include <asm/termios.h>
+
+#include "conv.h"
+#include "socksys.h"
+
+asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+
+static DEFINE_SPINLOCK(timod_pagelock);
+static char * page = NULL ;
+
+#ifndef DEBUG_SOLARIS_KMALLOC
+
+#define mykmalloc kmalloc
+#define mykfree kfree
+
+#else
+
+void * mykmalloc(size_t s, int gfp)
+{
+	static char * page;
+	static size_t free;
+	void * r;
+	s = ((s + 63) & ~63);
+	if( s > PAGE_SIZE ) {
+		SOLD("too big size, calling real kmalloc");
+		return kmalloc(s, gfp);
+	}
+	if( s > free ) {
+		/* we are wasting memory, but we don't care */
+		page = (char *)__get_free_page(gfp);
+		free = PAGE_SIZE;
+	}
+	r = page;
+	page += s;
+	free -= s;
+	return r;
+}
+
+void mykfree(void *p)
+{
+}
+
+#endif
+
+#ifndef DEBUG_SOLARIS
+
+#define BUF_SIZE	PAGE_SIZE
+#define PUT_MAGIC(a,m)
+#define SCHECK_MAGIC(a,m)
+#define BUF_OFFSET	0
+#define MKCTL_TRAILER	0
+
+#else
+
+#define BUF_SIZE	(PAGE_SIZE-2*sizeof(u64))
+#define BUFPAGE_MAGIC	0xBADC0DEDDEADBABEL
+#define MKCTL_MAGIC	0xDEADBABEBADC0DEDL
+#define PUT_MAGIC(a,m)	do{(*(u64*)(a))=(m);}while(0)
+#define SCHECK_MAGIC(a,m)	do{if((*(u64*)(a))!=(m))printk("%s,%u,%s(): magic %08x at %p corrupted!\n",\
+				__FILE__,__LINE__,__FUNCTION__,(m),(a));}while(0)
+#define BUF_OFFSET	sizeof(u64)
+#define MKCTL_TRAILER	sizeof(u64)
+
+#endif
+
+static char *getpage( void )
+{
+	char *r;
+	SOLD("getting page");
+	spin_lock(&timod_pagelock);
+	if (page) {
+		r = page;
+		page = NULL;
+		spin_unlock(&timod_pagelock);
+		SOLD("got cached");
+		return r + BUF_OFFSET;
+	}
+	spin_unlock(&timod_pagelock);
+	SOLD("getting new");
+	r = (char *)__get_free_page(GFP_KERNEL);
+	PUT_MAGIC(r,BUFPAGE_MAGIC);
+	PUT_MAGIC(r+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
+	return r + BUF_OFFSET;
+}
+
+static void putpage(char *p)
+{
+	SOLD("putting page");
+	p = p - BUF_OFFSET;
+	SCHECK_MAGIC(p,BUFPAGE_MAGIC);
+	SCHECK_MAGIC(p+PAGE_SIZE-sizeof(u64),BUFPAGE_MAGIC);
+	spin_lock(&timod_pagelock);
+	if (page) {
+		spin_unlock(&timod_pagelock);
+		free_page((unsigned long)p);
+		SOLD("freed it");
+	} else {
+		page = p;
+		spin_unlock(&timod_pagelock);
+		SOLD("cached it");
+	}
+}
+
+static struct T_primsg *timod_mkctl(int size)
+{
+	struct T_primsg *it;
+
+	SOLD("creating primsg");
+	it = (struct T_primsg *)mykmalloc(size+sizeof(*it)-sizeof(s32)+2*MKCTL_TRAILER, GFP_KERNEL);
+	if (it) {
+		SOLD("got it");
+		it->pri = MSG_HIPRI;
+		it->length = size;
+		PUT_MAGIC((char*)((u64)(((char *)&it->type)+size+7)&~7),MKCTL_MAGIC);
+	}
+	return it;
+}
+
+static void timod_wake_socket(unsigned int fd)
+{
+	struct socket *sock;
+
+	SOLD("wakeing socket");
+	sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode);
+	wake_up_interruptible(&sock->wait);
+	read_lock(&sock->sk->sk_callback_lock);
+	if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
+		__kill_fasync(sock->fasync_list, SIGIO, POLL_IN);
+	read_unlock(&sock->sk->sk_callback_lock);
+	SOLD("done");
+}
+
+static void timod_queue(unsigned int fd, struct T_primsg *it)
+{
+	struct sol_socket_struct *sock;
+
+	SOLD("queuing primsg");
+	sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
+	it->next = sock->pfirst;
+	sock->pfirst = it;
+	if (!sock->plast)
+		sock->plast = it;
+	timod_wake_socket(fd);
+	SOLD("done");
+}
+
+static void timod_queue_end(unsigned int fd, struct T_primsg *it)
+{
+	struct sol_socket_struct *sock;
+
+	SOLD("queuing primsg at end");
+	sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
+	it->next = NULL;
+	if (sock->plast)
+		sock->plast->next = it;
+	else
+		sock->pfirst = it;
+	sock->plast = it;
+	SOLD("done");
+}
+
+static void timod_error(unsigned int fd, int prim, int terr, int uerr)
+{
+	struct T_primsg *it;
+	
+	SOLD("making error");
+	it = timod_mkctl(sizeof(struct T_error_ack));
+	if (it) {
+		struct T_error_ack *err = (struct T_error_ack *)&it->type;
+		
+		SOLD("got it");
+		err->PRIM_type = T_ERROR_ACK;
+		err->ERROR_prim = prim;
+		err->TLI_error = terr;
+		err->UNIX_error = uerr; /* FIXME: convert this */
+		timod_queue(fd, it);
+	}
+	SOLD("done");
+}
+
+static void timod_ok(unsigned int fd, int prim)
+{
+	struct T_primsg *it;
+	struct T_ok_ack *ok;
+	
+	SOLD("creating ok ack");
+	it = timod_mkctl(sizeof(*ok));
+	if (it) {
+		SOLD("got it");
+		ok = (struct T_ok_ack *)&it->type;
+		ok->PRIM_type = T_OK_ACK;
+		ok->CORRECT_prim = prim;
+		timod_queue(fd, it);
+	}
+	SOLD("done");
+}
+
+static int timod_optmgmt(unsigned int fd, int flag, char __user *opt_buf, int opt_len, int do_ret)
+{
+	int error, failed;
+	int ret_space, ret_len;
+	long args[5];
+	char *ret_pos,*ret_buf;
+	int (*sys_socketcall)(int, unsigned long *) =
+		(int (*)(int, unsigned long *))SYS(socketcall);
+	mm_segment_t old_fs = get_fs();
+
+	SOLD("entry");
+	SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret));
+	if (!do_ret && (!opt_buf || opt_len <= 0))
+		return 0;
+	SOLD("getting page");
+	ret_pos = ret_buf = getpage();
+	ret_space = BUF_SIZE;
+	ret_len = 0;
+	
+	error = failed = 0;
+	SOLD("looping");
+	while(opt_len >= sizeof(struct opthdr)) {
+		struct opthdr *opt;
+		int orig_opt_len; 
+		SOLD("loop start");
+		opt = (struct opthdr *)ret_pos; 
+		if (ret_space < sizeof(struct opthdr)) {
+			failed = TSYSERR;
+			break;
+		}
+		SOLD("getting opthdr");
+		if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) ||
+			opt->len > opt_len) {
+			failed = TBADOPT;
+			break;
+		}
+		SOLD("got opthdr");
+		if (flag == T_NEGOTIATE) {
+			char *buf;
+			
+			SOLD("handling T_NEGOTIATE");
+			buf = ret_pos + sizeof(struct opthdr);
+			if (ret_space < opt->len + sizeof(struct opthdr) ||
+				copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) {
+				failed = TSYSERR;
+				break;
+			}
+			SOLD("got optdata");
+			args[0] = fd;
+			args[1] = opt->level;
+			args[2] = opt->name;
+			args[3] = (long)buf;
+			args[4] = opt->len;
+			SOLD("calling SETSOCKOPT");
+			set_fs(KERNEL_DS);
+			error = sys_socketcall(SYS_SETSOCKOPT, args);
+			set_fs(old_fs);
+			if (error) {
+				failed = TBADOPT;
+				break;
+			}
+			SOLD("SETSOCKOPT ok");
+		}
+		orig_opt_len = opt->len;
+		opt->len = ret_space - sizeof(struct opthdr);
+		if (opt->len < 0) {
+			failed = TSYSERR;
+			break;
+		}
+		args[0] = fd;
+		args[1] = opt->level;
+		args[2] = opt->name;
+		args[3] = (long)(ret_pos+sizeof(struct opthdr));
+		args[4] = (long)&opt->len;
+		SOLD("calling GETSOCKOPT");
+		set_fs(KERNEL_DS);
+		error = sys_socketcall(SYS_GETSOCKOPT, args);
+		set_fs(old_fs);
+		if (error) {
+			failed = TBADOPT;
+			break;
+		}
+		SOLD("GETSOCKOPT ok");
+		ret_space -= sizeof(struct opthdr) + opt->len;
+		ret_len += sizeof(struct opthdr) + opt->len;
+		ret_pos += sizeof(struct opthdr) + opt->len;
+		opt_len -= sizeof(struct opthdr) + orig_opt_len;
+		opt_buf += sizeof(struct opthdr) + orig_opt_len;
+		SOLD("loop end");
+	}
+	SOLD("loop done");
+	if (do_ret) {
+		SOLD("generating ret msg");
+		if (failed)
+			timod_error(fd, T_OPTMGMT_REQ, failed, -error);
+		else {
+			struct T_primsg *it;
+			it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len);
+			if (it) {
+				struct T_optmgmt_ack *ack =
+					(struct T_optmgmt_ack *)&it->type;
+				SOLD("got primsg");
+				ack->PRIM_type = T_OPTMGMT_ACK;
+				ack->OPT_length = ret_len;
+				ack->OPT_offset = sizeof(struct T_optmgmt_ack);
+				ack->MGMT_flags = (failed ? T_FAILURE : flag);
+				memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack),
+					ret_buf, ret_len);
+				timod_queue(fd, it);
+			}
+		}
+	}
+	SOLDD(("put_page %p\n", ret_buf));
+	putpage(ret_buf);
+	SOLD("done");	
+	return 0;
+}
+
+int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len,
+			char __user *data_buf, int data_len, int flags)
+{
+	int ret, error, terror;
+	char *buf;
+	struct file *filp;
+	struct inode *ino;
+	struct sol_socket_struct *sock;
+	mm_segment_t old_fs = get_fs();
+	long args[6];
+	int (*sys_socketcall)(int, unsigned long __user *) =
+		(int (*)(int, unsigned long __user *))SYS(socketcall);
+	int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int) =
+		(int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int))SYS(sendto);
+	filp = current->files->fd[fd];
+	ino = filp->f_dentry->d_inode;
+	sock = (struct sol_socket_struct *)filp->private_data;
+	SOLD("entry");
+	if (get_user(ret, (int __user *)A(ctl_buf)))
+		return -EFAULT;
+	switch (ret) {
+	case T_BIND_REQ:
+	{
+		struct T_bind_req req;
+		
+		SOLDD(("bind %016lx(%016lx)\n", sock, filp));
+		SOLD("T_BIND_REQ");
+		if (sock->state != TS_UNBND) {
+			timod_error(fd, T_BIND_REQ, TOUTSTATE, 0);
+			return 0;
+		}
+		SOLD("state ok");
+		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
+			timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
+			return 0;
+		}
+		SOLD("got ctl req");
+		if (req.ADDR_offset && req.ADDR_length) {
+			if (req.ADDR_length > BUF_SIZE) {
+				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
+				return 0;
+			}
+			SOLD("req size ok");
+			buf = getpage();
+			if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) {
+				timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT);
+				putpage(buf);
+				return 0;
+			}
+			SOLD("got ctl data");
+			args[0] = fd;
+			args[1] = (long)buf;
+			args[2] = req.ADDR_length;
+			SOLD("calling BIND");
+			set_fs(KERNEL_DS);
+			error = sys_socketcall(SYS_BIND, args);
+			set_fs(old_fs);
+			putpage(buf);
+			SOLD("BIND returned");
+		} else 
+			error = 0;
+		if (!error) {
+			struct T_primsg *it;
+			if (req.CONIND_number) {
+	  			args[0] = fd;
+  				args[1] = req.CONIND_number;
+  				SOLD("calling LISTEN");
+  				set_fs(KERNEL_DS);
+	  			error = sys_socketcall(SYS_LISTEN, args);
+  				set_fs(old_fs);
+  				SOLD("LISTEN done");
+  			}
+			it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr));
+			if (it) {
+				struct T_bind_ack *ack;
+
+				ack = (struct T_bind_ack *)&it->type;
+				ack->PRIM_type = T_BIND_ACK;
+				ack->ADDR_offset = sizeof(*ack);
+				ack->ADDR_length = sizeof(struct sockaddr);
+				ack->CONIND_number = req.CONIND_number;
+				args[0] = fd;
+				args[1] = (long)(ack+sizeof(*ack));
+				args[2] = (long)&ack->ADDR_length;
+				set_fs(KERNEL_DS);
+				sys_socketcall(SYS_GETSOCKNAME,args);
+				set_fs(old_fs);
+				sock->state = TS_IDLE;
+				timod_ok(fd, T_BIND_REQ);
+				timod_queue_end(fd, it);
+				SOLD("BIND done");
+				return 0;
+			}
+		}
+		SOLD("some error");
+		switch (error) {
+			case -EINVAL:
+				terror = TOUTSTATE;
+				error = 0;
+				break;
+			case -EACCES:
+				terror = TACCES;
+				error = 0;
+				break;
+			case -EADDRNOTAVAIL:
+			case -EADDRINUSE:
+				terror = TNOADDR;
+				error = 0;
+				break;
+			default:
+				terror = TSYSERR;
+				break;
+		}
+		timod_error(fd, T_BIND_REQ, terror, -error);
+		SOLD("BIND done");
+		return 0;
+	}
+	case T_CONN_REQ:
+	{
+		struct T_conn_req req;
+		unsigned short oldflags;
+		struct T_primsg *it;
+		SOLD("T_CONN_REQ");
+		if (sock->state != TS_UNBND && sock->state != TS_IDLE) {
+			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
+			return 0;
+		}
+		SOLD("state ok");
+		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
+			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+			return 0;
+		}
+		SOLD("got ctl req");
+		if (ctl_len > BUF_SIZE) {
+			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+			return 0;
+		}
+		SOLD("req size ok");
+		buf = getpage();
+		if (copy_from_user(buf, ctl_buf, ctl_len)) {
+			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+			putpage(buf);
+			return 0;
+		}
+#ifdef DEBUG_SOLARIS		
+		{
+			char * ptr = buf;
+			int len = ctl_len;
+			printk("returned data (%d bytes): ",len);
+			while( len-- ) {
+				if (!(len & 7))
+					printk(" ");
+				printk("%02x",(unsigned char)*ptr++);
+			}
+			printk("\n");
+		}
+#endif
+		SOLD("got ctl data");
+		args[0] = fd;
+		args[1] = (long)buf+req.DEST_offset;
+		args[2] = req.DEST_length;
+		oldflags = filp->f_flags;
+		filp->f_flags &= ~O_NONBLOCK;
+		SOLD("calling CONNECT");
+		set_fs(KERNEL_DS);
+		error = sys_socketcall(SYS_CONNECT, args);
+		set_fs(old_fs);
+		filp->f_flags = oldflags;
+		SOLD("CONNECT done");
+		if (!error) {
+			struct T_conn_con *con;
+			SOLD("no error");
+			it = timod_mkctl(ctl_len);
+			if (!it) {
+				putpage(buf);
+				return -ENOMEM;
+			}
+			con = (struct T_conn_con *)&it->type;
+#ifdef DEBUG_SOLARIS			
+			{
+				char * ptr = buf;
+				int len = ctl_len;
+				printk("returned data (%d bytes): ",len);
+				while( len-- ) {
+					if (!(len & 7))
+						printk(" ");
+					printk("%02x",(unsigned char)*ptr++);
+				}
+				printk("\n");
+			}
+#endif
+			memcpy(con, buf, ctl_len);
+			SOLD("copied ctl_buf");
+			con->PRIM_type = T_CONN_CON;
+			sock->state = TS_DATA_XFER;
+		} else {
+			struct T_discon_ind *dis;
+			SOLD("some error");
+			it = timod_mkctl(sizeof(*dis));
+			if (!it) {
+				putpage(buf);
+				return -ENOMEM;
+			}
+			SOLD("got primsg");
+			dis = (struct T_discon_ind *)&it->type;
+			dis->PRIM_type = T_DISCON_IND;
+			dis->DISCON_reason = -error;	/* FIXME: convert this as in iABI_errors() */
+			dis->SEQ_number = 0;
+		}
+		putpage(buf);
+		timod_ok(fd, T_CONN_REQ);
+		it->pri = 0;
+		timod_queue_end(fd, it);
+		SOLD("CONNECT done");
+		return 0;
+	}
+	case T_OPTMGMT_REQ:
+	{
+		struct T_optmgmt_req req;
+		SOLD("OPTMGMT_REQ");
+		if (copy_from_user(&req, ctl_buf, sizeof(req)))
+			return -EFAULT;
+		SOLD("got req");
+		return timod_optmgmt(fd, req.MGMT_flags,
+				req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL,
+				req.OPT_length, 1);
+	}
+	case T_UNITDATA_REQ:
+	{
+		struct T_unitdata_req req;
+		
+		int err;
+		SOLD("T_UNITDATA_REQ");
+		if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) {
+			timod_error(fd, T_CONN_REQ, TOUTSTATE, 0);
+			return 0;
+		}
+		SOLD("state ok");
+		if (copy_from_user(&req, ctl_buf, sizeof(req))) {
+			timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT);
+			return 0;
+		}
+		SOLD("got ctl req");
+#ifdef DEBUG_SOLARIS		
+		{
+			char * ptr = ctl_buf+req.DEST_offset;
+			int len = req.DEST_length;
+			printk("socket address (%d bytes): ",len);
+			while( len-- ) {
+				char c;
+				if (get_user(c,ptr))
+					printk("??");
+				else
+					printk("%02x",(unsigned char)c);
+				ptr++;
+			}
+			printk("\n");
+		}
+#endif		
+		err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr __user *)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length);
+		if (err == data_len)
+			return 0;
+		if(err >= 0) {
+			printk("timod: sendto failed to send all the data\n");
+			return 0;
+		}
+		timod_error(fd, T_CONN_REQ, TSYSERR, -err);
+		return 0;
+	}
+	default:
+		printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret);
+		break;
+	}
+	return -EINVAL;
+}
+
+int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __user *ctl_len,
+			char __user *data_buf, int data_maxlen, s32 __user *data_len, int *flags_p)
+{
+	int error;
+	int oldflags;
+	struct file *filp;
+	struct inode *ino;
+	struct sol_socket_struct *sock;
+	struct T_unitdata_ind udi;
+	mm_segment_t old_fs = get_fs();
+	long args[6];
+	char __user *tmpbuf;
+	int tmplen;
+	int (*sys_socketcall)(int, unsigned long __user *) =
+		(int (*)(int, unsigned long __user *))SYS(socketcall);
+	int (*sys_recvfrom)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *);
+	
+	SOLD("entry");
+	SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
+	filp = current->files->fd[fd];
+	ino = filp->f_dentry->d_inode;
+	sock = (struct sol_socket_struct *)filp->private_data;
+	SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
+	if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
+		&& sock->state == TS_IDLE) {
+		SOLD("calling LISTEN");
+		args[0] = fd;
+		args[1] = -1;
+		set_fs(KERNEL_DS);
+		sys_socketcall(SYS_LISTEN, args);
+		set_fs(old_fs);
+		SOLD("LISTEN done");
+	}
+	if (!(filp->f_flags & O_NONBLOCK)) {
+		struct poll_wqueues wait_table;
+		poll_table *wait;
+
+		poll_initwait(&wait_table);
+		wait = &wait_table.pt;
+		for(;;) {
+			SOLD("loop");
+			set_current_state(TASK_INTERRUPTIBLE);
+			/* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+			/* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+			/* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+			/* ( l>=0 && ( l<0 || ( pfirst && ! (flags == HIPRI && pri != HIPRI) ) ) ) */ 
+			/* ( l>=0 && ( l<0 || ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) ) */ 
+			/* ( l>=0 && ( pfirst && (flags != HIPRI || pri == HIPRI) ) ) */ 
+			if (ctl_maxlen >= 0 && sock->pfirst && (*flags_p != MSG_HIPRI || sock->pfirst->pri == MSG_HIPRI))
+				break;
+			SOLD("cond 1 passed");
+			if (
+			#if 1
+				*flags_p != MSG_HIPRI &&
+			#endif
+				((filp->f_op->poll(filp, wait) & POLLIN) ||
+				(filp->f_op->poll(filp, NULL) & POLLIN) ||
+				signal_pending(current))
+			) {
+				break;
+			}
+			if( *flags_p == MSG_HIPRI ) {
+				SOLD("avoiding lockup");
+				break ;
+			}
+			if(wait_table.error) {
+				SOLD("wait-table error");
+				poll_freewait(&wait_table);
+				return wait_table.error;
+			}
+			SOLD("scheduling");
+			schedule();
+		}
+		SOLD("loop done");
+		current->state = TASK_RUNNING;
+		poll_freewait(&wait_table);
+		if (signal_pending(current)) {
+			SOLD("signal pending");
+			return -EINTR;
+		}
+	}
+	if (ctl_maxlen >= 0 && sock->pfirst) {
+		struct T_primsg *it = sock->pfirst;
+		int l = min_t(int, ctl_maxlen, it->length);
+		SCHECK_MAGIC((char*)((u64)(((char *)&it->type)+sock->offset+it->length+7)&~7),MKCTL_MAGIC);
+		SOLD("purting ctl data");
+		if(copy_to_user(ctl_buf,
+			(char*)&it->type + sock->offset, l))
+			return -EFAULT;
+		SOLD("pur it");
+		if(put_user(l, ctl_len))
+			return -EFAULT;
+		SOLD("set ctl_len");
+		*flags_p = it->pri;
+		it->length -= l;
+		if (it->length) {
+			SOLD("more ctl");
+			sock->offset += l;
+			return MORECTL;
+		} else {
+			SOLD("removing message");
+			sock->pfirst = it->next;
+			if (!sock->pfirst)
+				sock->plast = NULL;
+			SOLDD(("getmsg kfree %016lx->%016lx\n", it, sock->pfirst));
+			mykfree(it);
+			sock->offset = 0;
+			SOLD("ctl done");
+			return 0;
+		}
+	}
+	*flags_p = 0;
+	if (ctl_maxlen >= 0) {
+		SOLD("ACCEPT perhaps?");
+		if (SOCKET_I(ino)->type == SOCK_STREAM && sock->state == TS_IDLE) {
+			struct T_conn_ind ind;
+			char *buf = getpage();
+			int len = BUF_SIZE;
+
+			SOLD("trying ACCEPT");
+			if (put_user(ctl_maxlen - sizeof(ind), ctl_len))
+				return -EFAULT;
+			args[0] = fd;
+			args[1] = (long)buf;
+			args[2] = (long)&len;
+			oldflags = filp->f_flags;
+			filp->f_flags |= O_NONBLOCK;
+			SOLD("calling ACCEPT");
+			set_fs(KERNEL_DS);
+			error = sys_socketcall(SYS_ACCEPT, args);
+			set_fs(old_fs);
+			filp->f_flags = oldflags;
+			if (error < 0) {
+				SOLD("some error");
+				putpage(buf);
+				return error;
+			}
+			if (error) {
+				SOLD("connect");
+				putpage(buf);
+				if (sizeof(ind) > ctl_maxlen) {
+					SOLD("generating CONN_IND");
+					ind.PRIM_type = T_CONN_IND;
+					ind.SRC_length = len;
+					ind.SRC_offset = sizeof(ind);
+					ind.OPT_length = ind.OPT_offset = 0;
+					ind.SEQ_number = error;
+					if(copy_to_user(ctl_buf, &ind, sizeof(ind))||
+					   put_user(sizeof(ind)+ind.SRC_length,ctl_len))
+						return -EFAULT;
+					SOLD("CONN_IND created");
+				}
+				if (data_maxlen >= 0)
+					put_user(0, data_len);
+				SOLD("CONN_IND done");
+				return 0;
+			}
+			if (len>ctl_maxlen) {
+				SOLD("data don't fit");
+				putpage(buf);
+				return -EFAULT;		/* XXX - is this ok ? */
+			}
+			if(copy_to_user(ctl_buf,buf,len) || put_user(len,ctl_len)){
+				SOLD("can't copy data");
+				putpage(buf);
+				return -EFAULT;
+			}
+			SOLD("ACCEPT done");
+			putpage(buf);
+		}
+	}
+	SOLD("checking data req");
+	if (data_maxlen <= 0) {
+		if (data_maxlen == 0)
+			put_user(0, data_len);
+		if (ctl_maxlen >= 0)
+			put_user(0, ctl_len);
+		return -EAGAIN;
+	}
+	SOLD("wants data");
+	if (ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
+		SOLD("udi fits");
+		tmpbuf = ctl_buf + sizeof(udi);
+		tmplen = ctl_maxlen - sizeof(udi);
+	} else {
+		SOLD("udi does not fit");
+		tmpbuf = NULL;
+		tmplen = 0;
+	}
+	if (put_user(tmplen, ctl_len))
+		return -EFAULT;
+	SOLD("set ctl_len");
+	oldflags = filp->f_flags;
+	filp->f_flags |= O_NONBLOCK;
+	SOLD("calling recvfrom");
+	sys_recvfrom = (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *))SYS(recvfrom);
+	error = sys_recvfrom(fd, data_buf, data_maxlen, 0, (struct sockaddr __user *)tmpbuf, ctl_len);
+	filp->f_flags = oldflags;
+	if (error < 0)
+		return error;
+	SOLD("error >= 0" ) ;
+	if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
+		SOLD("generating udi");
+		udi.PRIM_type = T_UNITDATA_IND;
+		if (get_user(udi.SRC_length, ctl_len))
+			return -EFAULT;
+		udi.SRC_offset = sizeof(udi);
+		udi.OPT_length = udi.OPT_offset = 0;
+		if (copy_to_user(ctl_buf, &udi, sizeof(udi)) ||
+		    put_user(sizeof(udi)+udi.SRC_length, ctl_len))
+			return -EFAULT;
+		SOLD("udi done");
+	} else {
+		if (put_user(0, ctl_len))
+			return -EFAULT;
+	}
+	put_user(error, data_len);
+	SOLD("done");
+	return 0;
+}
+
+asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
+{
+	struct file *filp;
+	struct inode *ino;
+	struct strbuf __user *ctlptr;
+	struct strbuf __user *datptr;
+	struct strbuf ctl, dat;
+	int __user *flgptr;
+	int flags;
+	int error = -EBADF;
+
+	SOLD("entry");
+	lock_kernel();
+	if(fd >= NR_OPEN) goto out;
+
+	filp = current->files->fd[fd];
+	if(!filp) goto out;
+
+	ino = filp->f_dentry->d_inode;
+	if (!ino || !S_ISSOCK(ino->i_mode))
+		goto out;
+
+	ctlptr = (struct strbuf __user *)A(arg1);
+	datptr = (struct strbuf __user *)A(arg2);
+	flgptr = (int __user *)A(arg3);
+
+	error = -EFAULT;
+
+	if (ctlptr) {
+		if (copy_from_user(&ctl,ctlptr,sizeof(struct strbuf)) || 
+		    put_user(-1,&ctlptr->len))
+			goto out;
+	} else
+		ctl.maxlen = -1;
+
+	if (datptr) {
+		if (copy_from_user(&dat,datptr,sizeof(struct strbuf)) || 
+		    put_user(-1,&datptr->len))
+			goto out;
+	} else
+		dat.maxlen = -1;
+
+	if (get_user(flags,flgptr))
+		goto out;
+
+	switch (flags) {
+	case 0:
+	case MSG_HIPRI:
+	case MSG_ANY:
+	case MSG_BAND:
+		break;
+	default:
+		error = -EINVAL;
+		goto out;
+	}
+
+	error = timod_getmsg(fd,A(ctl.buf),ctl.maxlen,&ctlptr->len,
+				A(dat.buf),dat.maxlen,&datptr->len,&flags);
+
+	if (!error && put_user(flags,flgptr))
+		error = -EFAULT;
+out:
+	unlock_kernel();
+	SOLD("done");
+	return error;
+}
+
+asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
+{
+	struct file *filp;
+	struct inode *ino;
+	struct strbuf __user *ctlptr;
+	struct strbuf __user *datptr;
+	struct strbuf ctl, dat;
+	int flags = (int) arg3;
+	int error = -EBADF;
+
+	SOLD("entry");
+	lock_kernel();
+	if(fd >= NR_OPEN) goto out;
+
+	filp = current->files->fd[fd];
+	if(!filp) goto out;
+
+	ino = filp->f_dentry->d_inode;
+	if (!ino) goto out;
+
+	if (!S_ISSOCK(ino->i_mode) &&
+		(imajor(ino) != 30 || iminor(ino) != 1))
+		goto out;
+
+	ctlptr = A(arg1);
+	datptr = A(arg2);
+
+	error = -EFAULT;
+
+	if (ctlptr) {
+		if (copy_from_user(&ctl,ctlptr,sizeof(ctl)))
+			goto out;
+		if (ctl.len < 0 && flags) {
+			error = -EINVAL;
+			goto out;
+		}
+	} else {
+		ctl.len = 0;
+		ctl.buf = 0;
+	}
+
+	if (datptr) {
+		if (copy_from_user(&dat,datptr,sizeof(dat)))
+			goto out;
+	} else {
+		dat.len = 0;
+		dat.buf = 0;
+	}
+
+	error = timod_putmsg(fd,A(ctl.buf),ctl.len,
+				A(dat.buf),dat.len,flags);
+out:
+	unlock_kernel();
+	SOLD("done");
+	return error;
+}