aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/syscall.c')
-rw-r--r--arch/mips/kernel/syscall.c112
1 files changed, 109 insertions, 3 deletions
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 8cf384644040..3fe1fcfa2e73 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -28,7 +28,9 @@
28#include <linux/compiler.h> 28#include <linux/compiler.h>
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/ipc.h> 30#include <linux/ipc.h>
31#include <linux/uaccess.h>
31 32
33#include <asm/asm.h>
32#include <asm/branch.h> 34#include <asm/branch.h>
33#include <asm/cachectl.h> 35#include <asm/cachectl.h>
34#include <asm/cacheflush.h> 36#include <asm/cacheflush.h>
@@ -290,12 +292,116 @@ SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
290 return 0; 292 return 0;
291} 293}
292 294
293asmlinkage int _sys_sysmips(long cmd, long arg1, long arg2, long arg3) 295static inline int mips_atomic_set(struct pt_regs *regs,
296 unsigned long addr, unsigned long new)
294{ 297{
298 unsigned long old, tmp;
299 unsigned int err;
300
301 if (unlikely(addr & 3))
302 return -EINVAL;
303
304 if (unlikely(!access_ok(VERIFY_WRITE, addr, 4)))
305 return -EINVAL;
306
307 if (cpu_has_llsc && R10000_LLSC_WAR) {
308 __asm__ __volatile__ (
309 " li %[err], 0 \n"
310 "1: ll %[old], (%[addr]) \n"
311 " move %[tmp], %[new] \n"
312 "2: sc %[tmp], (%[addr]) \n"
313 " beqzl %[tmp], 1b \n"
314 "3: \n"
315 " .section .fixup,\"ax\" \n"
316 "4: li %[err], %[efault] \n"
317 " j 3b \n"
318 " .previous \n"
319 " .section __ex_table,\"a\" \n"
320 " "STR(PTR)" 1b, 4b \n"
321 " "STR(PTR)" 2b, 4b \n"
322 " .previous \n"
323 : [old] "=&r" (old),
324 [err] "=&r" (err),
325 [tmp] "=&r" (tmp)
326 : [addr] "r" (addr),
327 [new] "r" (new),
328 [efault] "i" (-EFAULT)
329 : "memory");
330 } else if (cpu_has_llsc) {
331 __asm__ __volatile__ (
332 " li %[err], 0 \n"
333 "1: ll %[old], (%[addr]) \n"
334 " move %[tmp], %[new] \n"
335 "2: sc %[tmp], (%[addr]) \n"
336 " bnez %[tmp], 4f \n"
337 "3: \n"
338 " .subsection 2 \n"
339 "4: b 1b \n"
340 " .previous \n"
341 " \n"
342 " .section .fixup,\"ax\" \n"
343 "5: li %[err], %[efault] \n"
344 " j 3b \n"
345 " .previous \n"
346 " .section __ex_table,\"a\" \n"
347 " "STR(PTR)" 1b, 5b \n"
348 " "STR(PTR)" 2b, 5b \n"
349 " .previous \n"
350 : [old] "=&r" (old),
351 [err] "=&r" (err),
352 [tmp] "=&r" (tmp)
353 : [addr] "r" (addr),
354 [new] "r" (new),
355 [efault] "i" (-EFAULT)
356 : "memory");
357 } else {
358 do {
359 preempt_disable();
360 ll_bit = 1;
361 ll_task = current;
362 preempt_enable();
363
364 err = __get_user(old, (unsigned int *) addr);
365 err |= __put_user(new, (unsigned int *) addr);
366 if (err)
367 break;
368 rmb();
369 } while (!ll_bit);
370 }
371
372 if (unlikely(err))
373 return err;
374
375 regs->regs[2] = old;
376 regs->regs[7] = 0; /* No error */
377
378 /*
379 * Don't let your children do this ...
380 */
381 __asm__ __volatile__(
382 " move $29, %0 \n"
383 " j syscall_exit \n"
384 : /* no outputs */
385 : "r" (regs));
386
387 /* unreached. Honestly. */
388 while (1);
389}
390
391save_static_function(sys_sysmips);
392static int __used noinline
393_sys_sysmips(nabi_no_regargs struct pt_regs regs)
394{
395 long cmd, arg1, arg2, arg3;
396
397 cmd = regs.regs[4];
398 arg1 = regs.regs[5];
399 arg2 = regs.regs[6];
400 arg3 = regs.regs[7];
401
295 switch (cmd) { 402 switch (cmd) {
296 case MIPS_ATOMIC_SET: 403 case MIPS_ATOMIC_SET:
297 printk(KERN_CRIT "How did I get here?\n"); 404 return mips_atomic_set(&regs, arg1, arg2);
298 return -EINVAL;
299 405
300 case MIPS_FIXADE: 406 case MIPS_FIXADE:
301 if (arg1 & ~3) 407 if (arg1 & ~3)