diff options
author | Ulf Carlsson <md1ulfc@mdstud.chalmers.se> | 2000-04-05 00:43:25 +0000 |
---|---|---|
committer | Ulf Carlsson <md1ulfc@mdstud.chalmers.se> | 2000-04-05 00:43:25 +0000 |
commit | 687e82cd9a59b6a17e14bbe87c6f6ab299ff36ac (patch) | |
tree | 84603c565adc1fd399fd960de8c452a002cc66c0 /arch/mips64/kernel | |
parent | 126175087baaa93ba67a3528db48cafc444d783a (diff) |
o 32-bit ioctls (some at least)
o some syscalls
o check that the syscall is withing range
Diffstat (limited to 'arch/mips64/kernel')
-rw-r--r-- | arch/mips64/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/mips64/kernel/ioctl32.c | 529 | ||||
-rw-r--r-- | arch/mips64/kernel/linux32.c | 252 | ||||
-rw-r--r-- | arch/mips64/kernel/scall_64.S | 9 | ||||
-rw-r--r-- | arch/mips64/kernel/scall_o32.S | 24 |
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 |