diff options
Diffstat (limited to 'arch/mips/kernel/syscall.c')
-rw-r--r-- | arch/mips/kernel/syscall.c | 112 |
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 | ||
293 | asmlinkage int _sys_sysmips(long cmd, long arg1, long arg2, long arg3) | 295 | static 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 | |||
391 | save_static_function(sys_sysmips); | ||
392 | static 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(®s, arg1, arg2); |
298 | return -EINVAL; | ||
299 | 405 | ||
300 | case MIPS_FIXADE: | 406 | case MIPS_FIXADE: |
301 | if (arg1 & ~3) | 407 | if (arg1 & ~3) |