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