summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips64/kernel/Makefile2
-rw-r--r--arch/mips64/kernel/ioctl32.c529
-rw-r--r--arch/mips64/kernel/linux32.c252
-rw-r--r--arch/mips64/kernel/scall_64.S9
-rw-r--r--arch/mips64/kernel/scall_o32.S24
5 files changed, 793 insertions, 23 deletions
diff --git a/arch/mips64/kernel/Makefile b/arch/mips64/kernel/Makefile
index 8fb09b994..e1edfc6a7 100644
--- a/arch/mips64/kernel/Makefile
+++ b/arch/mips64/kernel/Makefile
@@ -18,7 +18,7 @@ O_OBJS := branch.o entry.o proc.o process.o ptrace.o r4k_cache.o r4k_fpu.o \
OX_OBJS := mips64_ksyms.o
ifdef CONFIG_MIPS32_COMPAT
-O_OBJS += linux32.o scall_o32.o signal32.o
+O_OBJS += linux32.o scall_o32.o signal32.o ioctl32.o
endif
ifdef CONFIG_BINFMT_ELF32
diff --git a/arch/mips64/kernel/ioctl32.c b/arch/mips64/kernel/ioctl32.c
new file mode 100644
index 000000000..b0b22a50d
--- /dev/null
+++ b/arch/mips64/kernel/ioctl32.c
@@ -0,0 +1,529 @@
+/* $Id$
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ *
+ * Mostly from the sparc64 ioctl32 implementation.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+
+#define A(__x) ((unsigned long)(__x))
+
+long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+struct timeval32 {
+ int tv_sec;
+ int tv_usec;
+};
+
+#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)
+#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)
+#define EXT2_IOC32_GETVERSION _IOR('v', 1, int)
+#define EXT2_IOC32_SETVERSION _IOW('v', 2, int)
+
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct timeval32 *up = (struct timeval32 *)arg;
+ struct timeval ktv;
+ mm_segment_t old_fs = get_fs();
+ int err;
+
+ set_fs(KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+ set_fs(old_fs);
+ if(!err) {
+ err = put_user(ktv.tv_sec, &up->tv_sec);
+ err |= __put_user(ktv.tv_usec, &up->tv_usec);
+ }
+ return err;
+}
+
+struct ifmap32 {
+ unsigned int mem_start;
+ unsigned int mem_end;
+ unsigned short base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN 6
+#define IFNAMSIZ 16
+ union {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct ifmap32 ifru_map;
+ char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ char ifru_newname[IFNAMSIZ];
+ __kernel_caddr_t32 ifru_data;
+ } ifr_ifru;
+};
+
+struct ifconf32 {
+ int ifc_len; /* size of buffer */
+ __kernel_caddr_t32 ifcbuf;
+};
+
+static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct ireq32 *uir32 = (struct ireq32 *)arg;
+ struct net_device *dev;
+ struct ifreq32 ifr32;
+
+ if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32)))
+ return -EFAULT;
+
+ read_lock(&dev_base_lock);
+ dev = __dev_get_by_index(ifr32.ifr_ifindex);
+ if (!dev) {
+ read_unlock(&dev_base_lock);
+ return -ENODEV;
+ }
+
+ strcpy(ifr32.ifr_name, dev->name);
+ read_unlock(&dev_base_lock);
+
+ if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static inline int dev_ifconf(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ioconf32 *uifc32 = (struct ioconf32 *)arg;
+ struct ifconf32 ifc32;
+ struct ifconf ifc;
+ struct ifreq32 *ifr32;
+ struct ifreq *ifr;
+ mm_segment_t old_fs;
+ int len;
+ int err;
+
+ if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32)))
+ return -EFAULT;
+
+ if(ifc32.ifcbuf == 0) {
+ ifc32.ifc_len = 0;
+ ifc.ifc_len = 0;
+ ifc.ifc_buf = NULL;
+ } else {
+ ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) *
+ sizeof (struct ifreq);
+ ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+ if (!ifc.ifc_buf)
+ return -ENOMEM;
+ }
+ ifr = ifc.ifc_req;
+ ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+ len = ifc32.ifc_len / sizeof (struct ifreq32);
+ while (len--) {
+ if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);
+ set_fs (old_fs);
+ if (err)
+ goto out;
+
+ ifr = ifc.ifc_req;
+ ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+ len = ifc.ifc_len / sizeof (struct ifreq);
+ ifc32.ifc_len = len * sizeof (struct ifreq32);
+
+ while (len--) {
+ if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) {
+ err = -EFAULT;
+ goto out;
+ }
+out:
+ if(ifc.ifc_buf != NULL)
+ kfree (ifc.ifc_buf);
+ return err;
+}
+
+static inline int dev_ifsioc(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ifreq32 *uifr = (struct ifreq32 *)arg;
+ struct ifreq ifr;
+ mm_segment_t old_fs;
+ int err;
+
+ switch (cmd) {
+ case SIOCSIFMAP:
+ err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name));
+ err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
+ err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
+ err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
+ err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
+ err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
+ err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
+ if (err)
+ return -EFAULT;
+ break;
+ default:
+ if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32)))
+ return -EFAULT;
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+ set_fs (old_fs);
+ if (!err) {
+ switch (cmd) {
+ case SIOCGIFFLAGS:
+ case SIOCGIFMETRIC:
+ case SIOCGIFMTU:
+ case SIOCGIFMEM:
+ case SIOCGIFHWADDR:
+ case SIOCGIFINDEX:
+ case SIOCGIFADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFNETMASK:
+ case SIOCGIFTXQLEN:
+ if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32)))
+ return -EFAULT;
+ break;
+ case SIOCGIFMAP:
+ err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name));
+ err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
+ err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
+ err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
+ err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
+ err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
+ err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
+ if (err)
+ err = -EFAULT;
+ break;
+ }
+ }
+ return err;
+}
+
+struct rtentry32
+{
+ unsigned int rt_pad1;
+ struct sockaddr rt_dst; /* target address */
+ struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
+ struct sockaddr rt_genmask; /* target network mask (IP) */
+ unsigned short rt_flags;
+ short rt_pad2;
+ unsigned int rt_pad3;
+ unsigned int rt_pad4;
+ short rt_metric; /* +1 for binary compatibility! */
+ unsigned int rt_dev; /* forcing the device at add */
+ unsigned int rt_mtu; /* per route MTU/Window */
+#ifndef __KERNEL__
+#define rt_mss rt_mtu /* Compatibility :-( */
+#endif
+ unsigned int rt_window; /* Window clamping */
+ unsigned short rt_irtt; /* Initial RTT */
+};
+
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct rtentry32 *ur = (struct rtentry32 *)arg;
+ struct rtentry r;
+ char devname[16];
+ u32 rtdev;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr));
+ ret |= __get_user (r.rt_flags, &(ur->rt_flags));
+ ret |= __get_user (r.rt_metric, &(ur->rt_metric));
+ ret |= __get_user (r.rt_mtu, &(ur->rt_mtu));
+ ret |= __get_user (r.rt_window, &(ur->rt_window));
+ ret |= __get_user (r.rt_irtt, &(ur->rt_irtt));
+ ret |= __get_user (rtdev, &(ur->rt_dev));
+ if (rtdev) {
+ ret |= copy_from_user (devname, (char *)A(rtdev), 15);
+ r.rt_dev = devname; devname[15] = 0;
+ } else
+ r.rt_dev = 0;
+ if (ret)
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_ioctl (fd, cmd, (long)&r);
+ set_fs (old_fs);
+ return ret;
+}
+
+static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ /* These are just misnamed, they actually get/put from/to user an int */
+ switch (cmd) {
+ case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+ case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+ case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+ case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+ }
+ return sys_ioctl(fd, cmd, arg);
+}
+
+static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ mm_segment_t old_fs = get_fs();
+ int err;
+ unsigned long val;
+
+ set_fs (KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&val);
+ set_fs (old_fs);
+ if (!err && put_user((unsigned int) val, (u32 *)arg))
+ return -EFAULT;
+ return err;
+}
+
+struct ioctl32_handler {
+ unsigned int cmd;
+ int (*function)(unsigned int, unsigned int, unsigned long);
+};
+
+struct ioctl32_list {
+ struct ioctl32_handler handler;
+ struct ioctl32_list *next;
+};
+
+#define IOCTL32_DEFAULT(cmd) { { cmd, (void *) sys_ioctl }, 0 }
+#define IOCTL32_HANDLER(cmd, handler) { { cmd, (void *) handler }, 0 }
+
+static struct ioctl32_list ioctl32_handler_table[] = {
+ IOCTL32_DEFAULT(TCGETA),
+ IOCTL32_DEFAULT(TCSETA),
+ IOCTL32_DEFAULT(TCSETAW),
+ IOCTL32_DEFAULT(TCSETAF),
+ IOCTL32_DEFAULT(TCSBRK),
+ IOCTL32_DEFAULT(TCXONC),
+ IOCTL32_DEFAULT(TCFLSH),
+ IOCTL32_DEFAULT(TCGETS),
+ IOCTL32_DEFAULT(TCSETS),
+ IOCTL32_DEFAULT(TCSETSW),
+ IOCTL32_DEFAULT(TCSETSF),
+ IOCTL32_DEFAULT(TIOCLINUX),
+
+ IOCTL32_DEFAULT(TIOCGETD),
+ IOCTL32_DEFAULT(TIOCSETD),
+ IOCTL32_DEFAULT(TIOCEXCL),
+ IOCTL32_DEFAULT(TIOCNXCL),
+ IOCTL32_DEFAULT(TIOCCONS),
+ IOCTL32_DEFAULT(TIOCGSOFTCAR),
+ IOCTL32_DEFAULT(TIOCSSOFTCAR),
+ IOCTL32_DEFAULT(TIOCSWINSZ),
+ IOCTL32_DEFAULT(TIOCGWINSZ),
+ IOCTL32_DEFAULT(TIOCMGET),
+ IOCTL32_DEFAULT(TIOCMBIC),
+ IOCTL32_DEFAULT(TIOCMBIS),
+ IOCTL32_DEFAULT(TIOCMSET),
+ IOCTL32_DEFAULT(TIOCPKT),
+ IOCTL32_DEFAULT(TIOCNOTTY),
+ IOCTL32_DEFAULT(TIOCSTI),
+ IOCTL32_DEFAULT(TIOCOUTQ),
+ IOCTL32_DEFAULT(TIOCSPGRP),
+ IOCTL32_DEFAULT(TIOCGPGRP),
+ IOCTL32_DEFAULT(TIOCSCTTY),
+ IOCTL32_DEFAULT(TIOCGPTN),
+ IOCTL32_DEFAULT(TIOCSPTLCK),
+ IOCTL32_DEFAULT(TIOCGSERIAL),
+ IOCTL32_DEFAULT(TIOCSSERIAL),
+ IOCTL32_DEFAULT(TIOCSERGETLSR),
+
+ IOCTL32_DEFAULT(FIOCLEX),
+ IOCTL32_DEFAULT(FIONCLEX),
+ IOCTL32_DEFAULT(FIOASYNC),
+ IOCTL32_DEFAULT(FIONBIO),
+ IOCTL32_DEFAULT(FIONREAD),
+
+ IOCTL32_DEFAULT(PIO_FONT),
+ IOCTL32_DEFAULT(GIO_FONT),
+ IOCTL32_DEFAULT(KDSIGACCEPT),
+ IOCTL32_DEFAULT(KDGETKEYCODE),
+ IOCTL32_DEFAULT(KDSETKEYCODE),
+ IOCTL32_DEFAULT(KIOCSOUND),
+ IOCTL32_DEFAULT(KDMKTONE),
+ IOCTL32_DEFAULT(KDGKBTYPE),
+ IOCTL32_DEFAULT(KDSETMODE),
+ IOCTL32_DEFAULT(KDGETMODE),
+ IOCTL32_DEFAULT(KDSKBMODE),
+ IOCTL32_DEFAULT(KDGKBMODE),
+ IOCTL32_DEFAULT(KDSKBMETA),
+ IOCTL32_DEFAULT(KDGKBMETA),
+ IOCTL32_DEFAULT(KDGKBENT),
+ IOCTL32_DEFAULT(KDSKBENT),
+ IOCTL32_DEFAULT(KDGKBSENT),
+ IOCTL32_DEFAULT(KDSKBSENT),
+ IOCTL32_DEFAULT(KDGKBDIACR),
+ IOCTL32_DEFAULT(KDSKBDIACR),
+ IOCTL32_DEFAULT(KDGKBLED),
+ IOCTL32_DEFAULT(KDSKBLED),
+ IOCTL32_DEFAULT(KDGETLED),
+ IOCTL32_DEFAULT(KDSETLED),
+ IOCTL32_DEFAULT(GIO_SCRNMAP),
+ IOCTL32_DEFAULT(PIO_SCRNMAP),
+ IOCTL32_DEFAULT(GIO_UNISCRNMAP),
+ IOCTL32_DEFAULT(PIO_UNISCRNMAP),
+ IOCTL32_DEFAULT(PIO_FONTRESET),
+ IOCTL32_DEFAULT(PIO_UNIMAPCLR),
+
+ IOCTL32_DEFAULT(VT_SETMODE),
+ IOCTL32_DEFAULT(VT_GETMODE),
+ IOCTL32_DEFAULT(VT_GETSTATE),
+ IOCTL32_DEFAULT(VT_OPENQRY),
+ IOCTL32_DEFAULT(VT_ACTIVATE),
+ IOCTL32_DEFAULT(VT_WAITACTIVE),
+ IOCTL32_DEFAULT(VT_RELDISP),
+ IOCTL32_DEFAULT(VT_DISALLOCATE),
+ IOCTL32_DEFAULT(VT_RESIZE),
+ IOCTL32_DEFAULT(VT_RESIZEX),
+ IOCTL32_DEFAULT(VT_LOCKSWITCH),
+ IOCTL32_DEFAULT(VT_UNLOCKSWITCH),
+
+ IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
+ IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
+ IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMETRIC, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMETRIC, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMTU, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMTU, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMEM, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMEM, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFHWADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFHWADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCADDMULTI, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCDELMULTI, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFINDEX, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMAP, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMAP, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFBRDADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFBRDADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFDSTADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFDSTADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFNETMASK, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFNETMASK, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFPFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFPFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFTXQLEN, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
+ IOCTL32_HANDLER(SIOCDELRT, routing_ioctl),
+
+ IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
+ IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
+ IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
+ IOCTL32_HANDLER(EXT2_IOC32_SETVERSION, do_ext2_ioctl),
+
+ IOCTL32_HANDLER(BLKGETSIZE, w_long)
+
+};
+
+#define NR_IOCTL32_HANDLERS (sizeof(ioctl32_handler_table) / \
+ sizeof(ioctl32_handler_table[0]))
+
+static struct ioctl32_list *ioctl32_hash_table[1024];
+
+static inline int ioctl32_hash(unsigned int cmd)
+{
+ return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
+}
+
+int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned int arg)
+{
+ int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+ struct file *filp;
+ struct ioctl32_list *l;
+ int error;
+
+ l = ioctl32_hash_table[ioctl32_hash(cmd)];
+
+ error = -EBADF;
+
+ filp = fget(fd);
+ if (!filp)
+ return error;
+
+ if (!filp->f_op || !filp->f_op->ioctl) {
+ error = sys_ioctl (fd, cmd, arg);
+ goto out;
+ }
+
+ while (l && l->handler.cmd != cmd)
+ l = l->next;
+
+ if (l) {
+ handler = (void *)l->handler.function;
+ error = handler(fd, cmd, arg, filp);
+ } else {
+ error = -EINVAL;
+ printk("unknown ioctl: %08x\n", cmd);
+ }
+out:
+ fput(filp);
+ return error;
+}
+
+static void ioctl32_insert(struct ioctl32_list *entry)
+{
+ int hash = ioctl32_hash(entry->handler.cmd);
+ if (!ioctl32_hash_table[hash])
+ ioctl32_hash_table[hash] = entry;
+ else {
+ struct ioctl32_list *l;
+ l = ioctl32_hash_table[hash];
+ while (l->next)
+ l = l->next;
+ l->next = entry;
+ entry->next = 0;
+ }
+}
+
+static int __init init_ioctl32(void)
+{
+ int i;
+ for (i = 0; i < NR_IOCTL32_HANDLERS; i++)
+ ioctl32_insert(&ioctl32_handler_table[i]);
+ return 0;
+}
+
+__initcall(init_ioctl32);
diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c
index 9ff6ea319..0ec965872 100644
--- a/arch/mips64/kernel/linux32.c
+++ b/arch/mips64/kernel/linux32.c
@@ -15,6 +15,7 @@
#include <linux/dirent.h>
#include <linux/resource.h>
#include <linux/highmem.h>
+#include <linux/time.h>
#include <asm/uaccess.h>
#include <asm/mman.h>
@@ -22,6 +23,79 @@
#define A(__x) ((unsigned long)(__x))
+#if 1
+static inline int
+putstat(struct stat32 *ubuf, struct stat *kbuf)
+{
+ int err;
+
+ err = put_user (kbuf->st_dev, &ubuf->st_dev);
+ err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
+ err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
+ err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
+ err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
+ err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
+ err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
+ err |= __put_user (kbuf->st_size, &ubuf->st_size);
+ err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
+ err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
+ err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
+ err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
+ err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+ return err;
+}
+
+extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
+
+asmlinkage int
+sys32_newstat(char * filename, struct stat32 *statbuf)
+{
+ int ret;
+ struct stat s;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newstat(filename, &s);
+ set_fs (old_fs);
+ if (putstat (statbuf, &s))
+ return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
+
+asmlinkage int
+sys32_newlstat(char * filename, struct stat32 *statbuf)
+{
+ int ret;
+ struct stat s;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newlstat(filename, &s);
+ set_fs (old_fs);
+ if (putstat (statbuf, &s))
+ return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
+
+asmlinkage int
+sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
+{
+ int ret;
+ struct stat s;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newfstat(fd, &s);
+ set_fs (old_fs);
+ if (putstat (statbuf, &s))
+ return -EFAULT;
+ return ret;
+}
+#else
/*
* Revalidate the inode. This is required for proper NFS attribute caching.
*/
@@ -146,12 +220,13 @@ asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 * statbuf)
unlock_kernel();
return err;
}
+#endif
asmlinkage int sys_mmap2(void) {return 0;}
asmlinkage long sys_truncate(const char * path, unsigned long length);
-asmlinkage int sys_truncate64(const char *path, unsigned long high,
- unsigned long low)
+asmlinkage int sys_truncate64(const char *path, unsigned int high,
+ unsigned int low)
{
if ((int)high < 0)
return -EINVAL;
@@ -160,8 +235,8 @@ asmlinkage int sys_truncate64(const char *path, unsigned long high,
asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
-asmlinkage int sys_ftruncate64(unsigned int fd, unsigned long high,
- unsigned long low)
+asmlinkage int sys_ftruncate64(unsigned int fd, unsigned int high,
+ unsigned int low)
{
if ((int)high < 0)
return -EINVAL;
@@ -501,6 +576,11 @@ struct timeval32
int tv_sec, tv_usec;
};
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
struct rusage32 {
struct timeval32 ru_utime;
@@ -694,3 +774,167 @@ sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
return ret;
}
+extern asmlinkage int
+sys_getrusage(int who, struct rusage *ru);
+
+asmlinkage int
+sys32_getrusage(int who, struct rusage32 *ru)
+{
+ struct rusage r;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getrusage(who, &r);
+ set_fs (old_fs);
+ if (put_rusage (ru, &r)) return -EFAULT;
+ return ret;
+}
+
+static inline long
+get_tv32(struct timeval *o, struct timeval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
+ return ENOSYS;
+}
+
+static inline long
+get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+ return ENOSYS;
+}
+
+static inline long
+put_tv32(struct timeval32 *o, struct timeval *i)
+{
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+static inline long
+put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
+ return ENOSYS;
+}
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+asmlinkage int
+sys32_getitimer(int which, struct itimerval32 *it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32(it, &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+
+asmlinkage int
+sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, in))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+ if (put_it32(out, &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+asmlinkage unsigned long
+sys32_alarm(unsigned int seconds)
+{
+ struct itimerval it_new, it_old;
+ unsigned int oldalarm;
+
+ it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
+ it_new.it_value.tv_sec = seconds;
+ it_new.it_value.tv_usec = 0;
+ do_setitimer(ITIMER_REAL, &it_new, &it_old);
+ oldalarm = it_old.it_value.tv_sec;
+ /* ehhh.. We can't return 0 if we have an alarm pending.. */
+ /* And we'd better return too much than too little anyway */
+ if (it_old.it_value.tv_usec)
+ oldalarm++;
+ return oldalarm;
+}
+
+/* Translations due to time_t size differences. Which affects all
+ sorts of things, like timeval and itimerval. */
+
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage int
+sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32(tv, &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int
+sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+ struct timeval ktv;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32(&ktv, tv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, tz, sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+extern asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
+ unsigned long offset_low, loff_t * result,
+ unsigned int origin);
+
+extern asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
+ unsigned int offset_low, loff_t * result,
+ unsigned int origin)
+{
+ return sys_llseek(fd, offset_high, offset_low, result, origin);
+}
diff --git a/arch/mips64/kernel/scall_64.S b/arch/mips64/kernel/scall_64.S
index af3dd1d87..224f43378 100644
--- a/arch/mips64/kernel/scall_64.S
+++ b/arch/mips64/kernel/scall_64.S
@@ -22,9 +22,6 @@
/* This duplicates the definition from <asm/signal.h> */
#define SIGILL 4 /* Illegal instruction (ANSI). */
-/* Highest syscall handled here. */
-#define MAX_SYSCALL_NO __NR_Linux + __NR_Linux_syscalls
-
#ifndef CONFIG_MIPS32_COMPAT
#define handle_sys64 handle_sys
#endif
@@ -39,14 +36,14 @@ NESTED(handle_sys64, PT_SIZE, sp)
#endif
ld t1, PT_EPC(sp) # skip syscall on return
- sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number
+ subu t0, v0, __NR_Linux # check syscall number
+ sltiu t0, t0, __NR_Linux_syscalls + 1
daddiu t1, 4 # skip to next instruction
beqz t0, illegal_syscall
sd t1, PT_EPC(sp)
- dsll t0, v0, 3
+ dsll t0, v0, 3 # offset into table
ld t2, (sys_call_table - (__NR_Linux * 8))(t0) # syscall routine
- beqz t2, illegal_syscall;
sd a3, PT_R26(sp) # save a3 for syscall restarting
diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S
index e47b1f31c..d1e21bff1 100644
--- a/arch/mips64/kernel/scall_o32.S
+++ b/arch/mips64/kernel/scall_o32.S
@@ -1,4 +1,4 @@
-/* $Id: scall_o32.S,v 1.17 2000/03/24 00:07:29 ulfc Exp $
+/* $Id: scall_o32.S,v 1.18 2000/03/27 21:04:13 ulfc Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -43,16 +43,16 @@ NESTED(handle_sys, PT_SIZE, sp)
#endif
ld t1, PT_EPC(sp) # skip syscall on return
- sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number
+ subu t0, v0, __NR_Linux32 # check syscall number
+ sltiu t0, t0, __NR_Linux32_syscalls + 1
daddiu t1, 4 # skip to next instruction
beqz t0, not_o32_scall
sd t1, PT_EPC(sp)
/* XXX Put both in one cacheline, should save a bit. */
- dsll t0, v0, 3
+ dsll t0, v0, 3 # offset into table
ld t2, (sys_call_table - (__NR_Linux32 * 8))(t0) # syscall routine
lbu t3, (sys_narg_table - __NR_Linux32)(v0) # number of arguments
- beqz t2, illegal_syscall;
subu t0, t3, 5 # 5 or more arguments?
sd a3, PT_R26(sp) # save a3 for syscall restarting
@@ -227,7 +227,7 @@ illegal_syscall:
sys sys_getuid 0
sys sys_stime 1 /* 4025 */
sys sys32_ptrace 4
- sys sys_alarm 1
+ sys sys32_alarm 1
sys sys_fstat 2
sys sys_ni_syscall 0
sys sys_utime 2 /* 4030 */
@@ -254,7 +254,7 @@ illegal_syscall:
sys sys_acct 0
sys sys_umount 2
sys sys_ni_syscall 0
- sys sys_ioctl 3
+ sys sys32_ioctl 3
sys sys_fcntl 3 /* 4055 */
sys sys_ni_syscall 2
sys sys_setpgid 2
@@ -277,9 +277,9 @@ illegal_syscall:
sys sys_sethostname 2
sys sys32_setrlimit 2 /* 4075 */
sys sys32_getrlimit 2
- sys sys_getrusage 2
- sys sys_gettimeofday 2
- sys sys_settimeofday 2
+ sys sys32_getrusage 2
+ sys sys32_gettimeofday 2
+ sys sys32_settimeofday 2
sys sys_getgroups 2 /* 4080 */
sys sys_setgroups 2
sys sys_ni_syscall 0 /* old_select */
@@ -304,8 +304,8 @@ illegal_syscall:
sys sys_ni_syscall 0 /* sys_ioperm */
sys sys_socketcall 2
sys sys_syslog 3
- sys sys_setitimer 3
- sys sys_getitimer 2 /* 4105 */
+ sys sys32_setitimer 3
+ sys sys32_getitimer 2 /* 4105 */
sys sys32_newstat 2
sys sys32_newlstat 2
sys sys32_newfstat 2
@@ -340,7 +340,7 @@ illegal_syscall:
sys sys_ni_syscall 0 /* for afs_syscall */
sys sys_setfsuid 1
sys sys_setfsgid 1
- sys sys_llseek 5 /* 4140 */
+ sys sys32_llseek 5 /* 4140 */
sys sys32_getdents 3
sys sys_select 5
sys sys_flock 2