[PATCH] solaris/sparc emul improvements against 2.2.11

Jason Rappleye (rappleye@nexus.hwi.buffalo.edu)
Fri, 20 Aug 1999 16:37:23 -0400


Hi,

Enclosed is a patch against kernel 2.2.11 that offers some improvements to
the solaris emulation. This patch was tested on a Sun Ultra 5 workstation.

-implemented F_FREESP (truncate) fcntl op
-socketpair seems to take just one arg on solairs, emul code was taking
three
-converted solaris socket options to linux equivalents (for setsockopt and
getsockopt). SO_STATE isn't emulated correctly, but for the app I was
working with it worked fine. If SO_STATE were documented....
-added MTIO (magnetic tape) ioctls
-added openprom ioctls (solaris eeprom works as expected)

The way I fixed socketpair is certainly not the right way to do it, but I
haven't figured out how change the number of arguments a syscall
takes...if someone would point me in the right direction I'd be happy to
fix it...I'm just not sure where to start.

Jason

--- v2.2.11/arch/sparc64/solaris/fs.c Wed Jun 2 12:55:38 1999
+++ linux/arch/sparc64/solaris/fs.c Thu Aug 19 16:50:29 1999
@@ -2,6 +2,9 @@
* 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>
@@ -19,6 +22,8 @@
#include <asm/string.h>
#include <asm/ptrace.h>

+#include <sys/syscall.h>
+
#include "conv.h"

extern char * getname32(u32 filename);
@@ -635,7 +640,7 @@
case SOL_F_GETLK:
case SOL_F_SETLK:
case SOL_F_SETLKW:
- {
+ {
struct flock f;
mm_segment_t old_fs = get_fs();

@@ -660,6 +665,15 @@
__put_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_pid, -EFAULT);
__put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT);
return ret;
+ }
+ case SOL_F_FREESP:
+ {
+ int length;
+ int (*sys_newftruncate)(unsigned int, unsigned long)=
+ (int (*)(unsigned int, unsigned long))SYS(ftruncate);
+
+ get_user_ret(length, &((struct sol_flock*)A(arg))->l_start, -EFAULT);
+ return sys_newftruncate(fd, length);
}
}
return -EINVAL;
--- v2.2.11/arch/sparc64/solaris/ioctl.c Tue Apr 14 20:44:21 1998
+++ linux/arch/sparc64/solaris/ioctl.c Thu Aug 19 16:50:46 1999
@@ -7,6 +7,9 @@
* 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>
@@ -18,9 +21,12 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/netdevice.h>
+#include <linux/mtio.h>
+#include <linux/time.h>

#include <asm/uaccess.h>
#include <asm/termios.h>
+#include <asm/openpromio.h>

#include "conv.h"
#include "socksys.h"
@@ -675,7 +681,7 @@
case 87: /* SIOCGIFNUM */
{
struct device *d;
- int i = 0;
+ int i = 0;

for (d = dev_base; d; d = d->next) i++;
if (put_user (i, (int *)A(arg)))
@@ -688,6 +694,72 @@

/* }}} */

+static inline int solaris_m(unsigned int fd, unsigned int cmd, u32 arg)
+{
+
+ struct file * flip;
+ flip=fget(fd);
+
+ switch (cmd & 0xff) {
+ case 1: /* MTIOCTOP */
+ return sys_ioctl(fd, MTIOCTOP, (unsigned long)&arg);
+ case 2: /* MTIOCGET */
+ return sys_ioctl(fd, MTIOCGET, (unsigned long)&arg);
+ 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 */
+ return -ENOSYS; /* linux doesn't support these */
+ }
+
+ return -ENOSYS;
+}
+
+static inline int solaris_O(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ switch (cmd & 0xff) {
+ case 1: /* OPROMGETOPT */
+ return sys_ioctl(fd, OPROMGETOPT, arg);
+ case 2: /* OPROMSETOPT */
+ return sys_ioctl(fd, OPROMSETOPT, arg);
+ case 3: /* OPROMNXTOPT */
+ return sys_ioctl(fd, OPROMNXTOPT, arg);
+ case 4: /* OPROMSETOPT2 */
+ return sys_ioctl(fd, OPROMSETOPT2, arg);
+ case 5: /* OPROMNEXT */
+ return sys_ioctl(fd, OPROMNEXT, arg);
+ case 6: /* OPROMCHILD */
+ return sys_ioctl(fd, OPROMCHILD, arg);
+ case 7: /* OPROMGETPROP */
+ return sys_ioctl(fd, OPROMGETPROP, arg);
+ case 8: /* OPROMNXTPROP */
+ return sys_ioctl(fd, OPROMNXTPROP, arg);
+ case 9: /* OPROMU2P */
+ return sys_ioctl(fd, OPROMU2P, arg);
+ case 10: /* OPROMGETCONS */
+ return sys_ioctl(fd, OPROMGETCONS, arg);
+ case 11: /* OPROMGETFBNAME */
+ return sys_ioctl(fd, OPROMGETFBNAME, arg);
+ case 12: /* OPROMGETBOOTARGS */
+ return sys_ioctl(fd, OPROMGETBOOTARGS, arg);
+ case 13: /* OPROMGETVERSION */
+ case 14: /* OPROMPATH2DRV */
+ case 15: /* OPROMDEV2PROMNAME */
+ case 16: /* OPROMPROM2DEVNAME */
+ case 17: /* OPROMGETPROPLEN */
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
struct file *filp;
@@ -695,6 +767,7 @@

lock_kernel();
filp = fcheck(fd);
+
if (!filp)
goto out;

@@ -707,19 +780,24 @@
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;
}
+
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;
}
+
unlock_kernel();
return error;
}
+
--- v2.2.11/arch/sparc64/solaris/socket.c Mon Nov 16 13:37:28 1998
+++ linux/arch/sparc64/solaris/socket.c Thu Aug 19 16:50:58 1999
@@ -2,6 +2,9 @@
* 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>
@@ -25,6 +28,18 @@
#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)
@@ -40,6 +55,19 @@
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) =
@@ -55,9 +83,12 @@
int (*sys_socketpair)(int, int, int, int *) =
(int (*)(int, int, int, int *))SYS(socketpair);

- type = socket_check (family, type);
- if (type < 0) return type;
- return sys_socketpair(family, type, protocol, usockvec);
+ /* 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 family */
+
+ return sys_socketpair(AF_UNIX, SOCK_STREAM, 0, (int *)family);
}

asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen)
@@ -68,10 +99,19 @@
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);
+ int val;
+
+ optname = solaris_to_linux_sockopt(optname);
+ get_user_ret(val, (int *)A(optval), -EFAULT);
+ printk("solaris_setsockopt: optname (%#x) optval (%#x)\n", optname, val);
+
+ if (optname < 0) return optname;
+ if (optname == SO_STATE) return 0;

return sunos_setsockopt(fd, level, optname, optval, optlen);
}
@@ -80,6 +120,11 @@
{
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);
}
--- v2.2.11/drivers/sbus/char/openprom.c Mon Aug 24 16:14:09 1998
+++ linux/drivers/sbus/char/openprom.c Thu Aug 19 15:55:12 1999
@@ -70,10 +70,22 @@
return -EFAULT;

get_user_ret(bufsize, &info->oprom_size, -EFAULT);
-
- if (bufsize == 0 || bufsize > OPROMMAXPARAM)
+#if 0
+ if (bufsize == 0 || bufsize > OPROMMAXPARAM)
+ return -EINVAL;
+#endif
+ if (bufsize == 0)
return -EINVAL;

+ /* max buf size is higher on solaris...maybe the right way to
+ do this is to change the value of OPROMMAXPARAM in the
+ header file ? */
+
+ if (bufsize > OPROMMAXPARAM) {
+ /* printk(KERN_DEBUG "openprom.c: bufsize hack\n"); */
+ bufsize = OPROMMAXPARAM;
+ }
+
if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
return -ENOMEM;
memset(*opp_p, 0, sizeof(int) + bufsize + 1);
@@ -144,7 +156,7 @@
else
bufsize = copyin((void *)arg, &opp);

- if (bufsize < 0)
+ if (bufsize < 0)
return bufsize;

switch (cmd) {

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/