1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/*
* MIPS specific syscalls
*
* 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
* for more details.
*
* Copyright (C) 1995, 1996, 1997, 2000 by Ralf Baechle
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/utsname.h>
#include <asm/cachectl.h>
#include <asm/pgalloc.h>
#include <asm/sysmips.h>
#include <asm/uaccess.h>
extern asmlinkage void syscall_trace(void);
/*
* How long a hostname can we get from user space?
* -EFAULT if invalid area or too long
* 0 if ok
* >0 EFAULT after xx bytes
*/
static inline int
get_max_hostname(unsigned long address)
{
struct vm_area_struct * vma;
vma = find_vma(current->mm, address);
if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
return -EFAULT;
address = vma->vm_end - address;
if (address > PAGE_SIZE)
return 0;
if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
(vma->vm_next->vm_flags & VM_READ))
return 0;
return address;
}
asmlinkage int
sys_sysmips(int cmd, int arg1, int arg2, int arg3)
{
int *p;
char *name;
int tmp, len, retval, errno;
switch(cmd) {
case SETNAME: {
char nodename[__NEW_UTS_LEN + 1];
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
name = (char *) arg1;
len = strncpy_from_user(nodename, name, sizeof(nodename));
if (len < 0)
return -EFAULT;
down_write(&uts_sem);
strncpy(system_utsname.nodename, name, len);
up_write(&uts_sem);
system_utsname.nodename[len] = '\0';
return 0;
}
case MIPS_ATOMIC_SET: {
#ifdef CONFIG_CPU_HAS_LLSC
unsigned int tmp;
p = (int *) arg1;
errno = verify_area(VERIFY_WRITE, p, sizeof(*p));
if (errno)
return errno;
errno = 0;
__asm__(".set\tpush\t\t\t# sysmips(MIPS_ATOMIC, ...)\n\t"
".set\tmips2\n\t"
".set\tnoat\n\t"
"1:\tll\t%0, %4\n\t"
"move\t$1, %3\n\t"
"2:\tsc\t$1, %1\n\t"
"beqz\t$1, 1b\n\t"
".set\tpop\n\t"
".section\t.fixup,\"ax\"\n"
"3:\tli\t%2, 1\t\t\t# error\n\t"
".previous\n\t"
".section\t__ex_table,\"a\"\n\t"
".word\t1b, 3b\n\t"
".word\t2b, 3b\n\t"
".previous\n\t"
: "=&r" (tmp), "=o" (* (u32 *) p), "=r" (errno)
: "r" (arg2), "o" (* (u32 *) p), "2" (errno)
: "$1");
if (errno)
return -EFAULT;
/* We're skipping error handling etc. */
if (current->ptrace & PT_TRACESYS)
syscall_trace();
((struct pt_regs *)&cmd)->regs[2] = tmp;
((struct pt_regs *)&cmd)->regs[7] = 0;
__asm__ __volatile__(
"move\t$29, %0\n\t"
"j\to32_ret_from_sys_call"
: /* No outputs */
: "r" (&cmd));
/* Unreached */
#else
printk("sys_sysmips(MIPS_ATOMIC_SET, ...) not ready for !CONFIG_CPU_HAS_LLSC\n");
#endif
}
case MIPS_FIXADE:
tmp = current->thread.mflags & ~3;
current->thread.mflags = tmp | (arg1 & 3);
retval = 0;
goto out;
case FLUSH_CACHE:
flush_cache_all();
retval = 0;
goto out;
case MIPS_RDNVRAM:
retval = -EIO;
goto out;
default:
retval = -EINVAL;
goto out;
}
out:
return retval;
}
/*
* No implemented yet ...
*/
asmlinkage int
sys_cachectl(char *addr, int nbytes, int op)
{
return -ENOSYS;
}
asmlinkage int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
schedule();
return -ERESTARTNOHAND;
}
|