1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1995, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2001 MIPS Technologies, Inc.
9 */
10 #include <linux/capability.h>
11 #include <linux/errno.h>
12 #include <linux/linkage.h>
13 #include <linux/fs.h>
14 #include <linux/smp.h>
15 #include <linux/ptrace.h>
16 #include <linux/string.h>
17 #include <linux/syscalls.h>
18 #include <linux/file.h>
19 #include <linux/utsname.h>
20 #include <linux/unistd.h>
21 #include <linux/sem.h>
22 #include <linux/msg.h>
23 #include <linux/shm.h>
24 #include <linux/compiler.h>
25 #include <linux/ipc.h>
26 #include <linux/uaccess.h>
27 #include <linux/slab.h>
28 #include <linux/elf.h>
29 #include <linux/prctl.h>
30
31 #include <asm/asm.h>
32 #include <asm/branch.h>
33 #include <asm/cachectl.h>
34 #include <asm/cacheflush.h>
35 #include <asm/asm-offsets.h>
36 #include <asm/signal.h>
37 #include <asm/sim.h>
38 #include <asm/shmparam.h>
39 #include <asm/sysmips.h>
40 #include <asm/uaccess.h>
41 #include <asm/switch_to.h>
42 #include <asm/fpu.h>
43
44 extern unsigned int system_has_fpu;
45 extern unsigned int global_fpu_id;
46 /*
47 * For historic reasons the pipe(2) syscall on MIPS has an unusual calling
48 * convention. It returns results in registers $v0 / $v1 which means there
49 * is no need for it to do verify the validity of a userspace pointer
50 * argument. Historically that used to be expensive in Linux. These days
51 * the performance advantage is negligible.
52 */
sysm_pipe(void)53 asmlinkage int sysm_pipe(void)
54 {
55 int fd[2];
56 int error = do_pipe_flags(fd, 0);
57 if (error)
58 return error;
59 current_pt_regs()->regs[3] = fd[1];
60 return fd[0];
61 }
62
SYSCALL_DEFINE6(mips_mmap,unsigned long,addr,unsigned long,len,unsigned long,prot,unsigned long,flags,unsigned long,fd,off_t,offset)63 SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
64 unsigned long, prot, unsigned long, flags, unsigned long,
65 fd, off_t, offset)
66 {
67 unsigned long result;
68
69 result = -EINVAL;
70 if (offset & ~PAGE_MASK)
71 goto out;
72
73 result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
74
75 out:
76 return result;
77 }
78
SYSCALL_DEFINE6(mips_mmap2,unsigned long,addr,unsigned long,len,unsigned long,prot,unsigned long,flags,unsigned long,fd,unsigned long,pgoff)79 SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
80 unsigned long, prot, unsigned long, flags, unsigned long, fd,
81 unsigned long, pgoff)
82 {
83 if (pgoff & (~PAGE_MASK >> 12))
84 return -EINVAL;
85
86 return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
87 }
88
89 save_static_function(sys_fork);
90 save_static_function(sys_clone);
91
SYSCALL_DEFINE1(set_thread_area,unsigned long,addr)92 SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
93 {
94 struct thread_info *ti = task_thread_info(current);
95
96 ti->tp_value = addr;
97 if (cpu_has_userlocal)
98 write_c0_userlocal(addr);
99
100 return 0;
101 }
102
mips_atomic_set(unsigned long addr,unsigned long new)103 static inline int mips_atomic_set(unsigned long addr, unsigned long new)
104 {
105 unsigned long old, tmp;
106 struct pt_regs *regs;
107 unsigned int err;
108
109 if (unlikely(addr & 3))
110 return -EINVAL;
111
112 if (unlikely(!access_ok(VERIFY_WRITE, addr, 4)))
113 return -EINVAL;
114
115 if (cpu_has_llsc && R10000_LLSC_WAR) {
116 __asm__ __volatile__ (
117 " .set mips3 \n"
118 " li %[err], 0 \n"
119 "1: ll %[old], (%[addr]) \n"
120 " move %[tmp], %[new] \n"
121 "2: sc %[tmp], (%[addr]) \n"
122 " beqzl %[tmp], 1b \n"
123 "3: \n"
124 " .section .fixup,\"ax\" \n"
125 "4: li %[err], %[efault] \n"
126 " j 3b \n"
127 " .previous \n"
128 " .section __ex_table,\"a\" \n"
129 " "STR(PTR)" 1b, 4b \n"
130 " "STR(PTR)" 2b, 4b \n"
131 " .previous \n"
132 " .set mips0 \n"
133 : [old] "=&r" (old),
134 [err] "=&r" (err),
135 [tmp] "=&r" (tmp)
136 : [addr] "r" (addr),
137 [new] "r" (new),
138 [efault] "i" (-EFAULT)
139 : "memory");
140 } else if (cpu_has_llsc) {
141 __asm__ __volatile__ (
142 #ifdef CONFIG_CPU_MIPSR6
143 " .set mips64r6 \n"
144 #else
145 " .set mips3 \n"
146 #endif
147 " li %[err], 0 \n"
148 "1: ll %[old], (%[addr]) \n"
149 " move %[tmp], %[new] \n"
150 "2: sc %[tmp], (%[addr]) \n"
151 " bnez %[tmp], 4f \n"
152 "3: \n"
153 " .subsection 2 \n"
154 "4: b 1b \n"
155 " .previous \n"
156 " \n"
157 " .section .fixup,\"ax\" \n"
158 "5: li %[err], %[efault] \n"
159 " j 3b \n"
160 " .previous \n"
161 " .section __ex_table,\"a\" \n"
162 " "STR(PTR)" 1b, 5b \n"
163 " "STR(PTR)" 2b, 5b \n"
164 " .previous \n"
165 " .set mips0 \n"
166 : [old] "=&r" (old),
167 [err] "=&r" (err),
168 [tmp] "=&r" (tmp)
169 : [addr] "r" (addr),
170 [new] "r" (new),
171 [efault] "i" (-EFAULT)
172 : "memory");
173 } else {
174 do {
175 preempt_disable();
176 ll_bit = 1;
177 ll_task = current;
178 preempt_enable();
179
180 err = __get_user(old, (unsigned int *) addr);
181 err |= __put_user(new, (unsigned int *) addr);
182 if (err)
183 break;
184 rmb();
185 } while (!ll_bit);
186 }
187
188 if (unlikely(err))
189 return err;
190
191 regs = current_pt_regs();
192 regs->regs[2] = old;
193 regs->regs[7] = 0; /* No error */
194
195 /*
196 * Don't let your children do this ...
197 */
198 __asm__ __volatile__(
199 " move $29, %0 \n"
200 " j syscall_exit \n"
201 : /* no outputs */
202 : "r" (regs));
203
204 /* unreached. Honestly. */
205 unreachable();
206 }
207
mips_lose_fpu(void)208 asmlinkage void mips_lose_fpu(void)
209 {
210 preempt_disable();
211 clear_thread_flag(TIF_FPU_LOSE_REQUEST);
212 lose_fpu_inatomic(1);
213 preempt_enable_no_resched();
214 }
215
mips_switch_fpu_mode(void * info)216 void mips_switch_fpu_mode(void *info)
217 {
218 struct mm_struct *mm = info;
219
220 if ((current->mm == mm) && (is_fpu_owner() || is_msa_enabled()))
221 set_thread_flag(TIF_FPU_LOSE_REQUEST);
222 }
223
mips_fpu_prctl(unsigned long type,unsigned long param)224 unsigned int mips_fpu_prctl(unsigned long type, unsigned long param)
225 {
226 register unsigned long val;
227 register unsigned long mask;
228 register unsigned long *addr;
229
230 switch (type) {
231 case PR_SET_FP_MODE:
232 if (param & ~(PR_FP_MODE_FR|PR_FP_MODE_FRE))
233 return -EINVAL;
234
235 #ifndef CONFIG_MIPS_INCOMPATIBLE_ARCH_EMULATION
236 if (system_has_fpu) {
237 if ((param & PR_FP_MODE_FRE) && !cpu_has_fre)
238 return -EOPNOTSUPP;
239 if ((param & PR_FP_MODE_FR) && !(global_fpu_id & MIPS_FPIR_F64))
240 return -EOPNOTSUPP;
241 if (!(param & PR_FP_MODE_FR)) {
242 unsigned int res;
243 unsigned int status;
244
245 /* test FPU with FR0 capability */
246 local_irq_disable();
247 status = change_c0_status(ST0_FR|ST0_CU1, ST0_CU1);
248 enable_fpu_hazard();
249 res = read_c0_status();
250 write_c0_status(status);
251 disable_fpu_hazard();
252 local_irq_enable();
253 if (res & ST0_FR)
254 return -EOPNOTSUPP;
255 }
256 }
257 #endif
258 val = (param & PR_FP_MODE_FR)? LTIF_FPU_FR : 0;
259 val |= (param & PR_FP_MODE_FRE)? LTIF_FPU_FRE : 0;
260 mask = ~(LTIF_FPU_FR|LTIF_FPU_FRE);
261 preempt_disable();
262 addr = &(current->mm->context.thread_flags);
263 __asm__ __volatile__(
264 ".set push \n"
265 ".set noreorder \n"
266 ".set noat \n"
267 #ifdef CONFIG_64BIT
268 "1: lld $1, 0(%0) \n"
269 " and $1, $1, %1 \n"
270 " or $1, $1, %2 \n"
271 " scd $1, 0(%0) \n"
272 #else
273 "1: ll $1, 0(%0) \n"
274 " and $1, $1, %1 \n"
275 " or $1, $1, %2 \n"
276 " sc $1, 0(%0) \n"
277 #endif
278 " beqz $1, 1b \n"
279 " nop \n"
280 ".set pop \n"
281 :
282 : "r"(addr), "r"(mask), "r"(val)
283 : "memory");
284 smp_llsc_mb();
285 /* send a "barrier" for FPU mode - force other CPUs to lose FPU */
286 if (atomic_read(¤t->mm->mm_users) != 1)
287 smp_call_function(mips_switch_fpu_mode, (void *)(current->mm), 1);
288 lose_fpu(1);
289 preempt_enable();
290 break;
291
292 case PR_GET_FP_MODE:
293 if (unlikely(param & 3))
294 return -EINVAL;
295
296 if (unlikely(!access_ok(VERIFY_WRITE, param, 4)))
297 return -EINVAL;
298
299 val = (current_thread_info()->local_flags & LTIF_FPU_FR)? PR_FP_MODE_FR : 0;
300 val |= (current_thread_info()->local_flags & LTIF_FPU_FRE)? PR_FP_MODE_FRE : 0;
301 if (put_user(val, (unsigned long *)param))
302 return -EINVAL;
303 break;
304
305 default:
306 return -EINVAL;
307 }
308
309 return 0;
310 }
311
mips_get_process_fp_mode(struct task_struct * task)312 long mips_get_process_fp_mode(struct task_struct *task)
313 {
314 unsigned long val;
315
316 val = (((struct thread_info *)task_stack_page(task))->local_flags & LTIF_FPU_FR)? PR_FP_MODE_FR : 0;
317 val |= (((struct thread_info *)task_stack_page(task))->local_flags & LTIF_FPU_FRE)? PR_FP_MODE_FRE : 0;
318
319 return val;
320 }
321
mips_set_process_fp_mode(struct task_struct * task,unsigned long value)322 long mips_set_process_fp_mode(struct task_struct *task,
323 unsigned long value)
324 {
325 return mips_fpu_prctl(PR_SET_FP_MODE, value);
326 }
327
SYSCALL_DEFINE3(sysmips,long,cmd,long,arg1,long,arg2)328 SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
329 {
330 switch (cmd) {
331 case MIPS_ATOMIC_SET:
332 return mips_atomic_set(arg1, arg2);
333
334 case MIPS_FIXADE:
335 if (arg1 & ~3)
336 return -EINVAL;
337
338 if (arg1 & 1)
339 set_thread_flag(TIF_FIXADE);
340 else
341 clear_thread_flag(TIF_FIXADE);
342 if (arg1 & 2)
343 set_thread_flag(TIF_LOGADE);
344 else
345 clear_thread_flag(TIF_LOGADE);
346
347 return 0;
348
349 case FLUSH_CACHE:
350 __flush_cache_all();
351 return 0;
352
353 case MIPS_FPU_PRCTL:
354 return mips_fpu_prctl(arg1, arg2);
355 }
356
357 return -EINVAL;
358 }
359
360 /*
361 * No implemented yet ...
362 */
SYSCALL_DEFINE3(cachectl,char *,addr,int,nbytes,int,op)363 SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
364 {
365 return -ENOSYS;
366 }
367
368 /*
369 * If we ever come here the user sp is bad. Zap the process right away.
370 * Due to the bad stack signaling wouldn't work.
371 */
bad_stack(void)372 asmlinkage void bad_stack(void)
373 {
374 do_exit(SIGSEGV);
375 }
376