blob: 2454c44a8f54c11b99771784eb2f77974a4a3d9c [file] [log] [blame]
Jakub Jelinek4732efb2005-09-06 15:16:25 -07001#ifndef _ASM_FUTEX_H
2#define _ASM_FUTEX_H
3
4#ifdef __KERNEL__
5
Ralf Baechleebfaeba2005-09-15 08:52:34 +00006#include <linux/config.h>
Jakub Jelinek4732efb2005-09-06 15:16:25 -07007#include <linux/futex.h>
8#include <asm/errno.h>
9#include <asm/uaccess.h>
10
Ralf Baechleebfaeba2005-09-15 08:52:34 +000011#ifdef CONFIG_SMP
12#define __FUTEX_SMP_SYNC " sync \n"
13#else
14#define __FUTEX_SMP_SYNC
15#endif
16
17#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
18{ \
19 __asm__ __volatile__( \
20 " .set push \n" \
21 " .set noat \n" \
22 " .set mips3 \n" \
23 "1: ll %1, (%3) # __futex_atomic_op1 \n" \
24 " .set mips0 \n" \
25 " " insn " \n" \
26 " .set mips3 \n" \
27 "2: sc $1, (%3) \n" \
28 " beqzl $1, 1b \n" \
29 __FUTEX_SMP_SYNC \
30 "3: \n" \
31 " .set pop \n" \
32 " .set mips0 \n" \
33 " .section .fixup,\"ax\" \n" \
34 "4: li %0, %5 \n" \
35 " j 2b \n" \
36 " .previous \n" \
37 " .section __ex_table,\"a\" \n" \
38 " "__UA_ADDR "\t1b, 4b \n" \
39 " "__UA_ADDR "\t2b, 4b \n" \
40 " .previous \n" \
41 : "=r" (ret), "=r" (oldval) \
42 : "0" (0), "r" (uaddr), "Jr" (oparg), "i" (-EFAULT)); \
43}
44
Jakub Jelinek4732efb2005-09-06 15:16:25 -070045static inline int
46futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
47{
48 int op = (encoded_op >> 28) & 7;
49 int cmp = (encoded_op >> 24) & 15;
50 int oparg = (encoded_op << 8) >> 20;
51 int cmparg = (encoded_op << 20) >> 20;
52 int oldval = 0, ret;
53 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
54 oparg = 1 << oparg;
55
56 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
57 return -EFAULT;
58
59 inc_preempt_count();
60
61 switch (op) {
62 case FUTEX_OP_SET:
Ralf Baechleebfaeba2005-09-15 08:52:34 +000063 __futex_atomic_op("move $1, %z4", ret, oldval, uaddr, oparg);
64 break;
65
Jakub Jelinek4732efb2005-09-06 15:16:25 -070066 case FUTEX_OP_ADD:
Ralf Baechleebfaeba2005-09-15 08:52:34 +000067 __futex_atomic_op("addu $1, %1, %z4",
68 ret, oldval, uaddr, oparg);
69 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -070070 case FUTEX_OP_OR:
Ralf Baechleebfaeba2005-09-15 08:52:34 +000071 __futex_atomic_op("or $1, %1, %z4",
72 ret, oldval, uaddr, oparg);
73 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -070074 case FUTEX_OP_ANDN:
Ralf Baechleebfaeba2005-09-15 08:52:34 +000075 __futex_atomic_op("and $1, %1, %z4",
76 ret, oldval, uaddr, ~oparg);
77 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -070078 case FUTEX_OP_XOR:
Ralf Baechleebfaeba2005-09-15 08:52:34 +000079 __futex_atomic_op("xor $1, %1, %z4",
80 ret, oldval, uaddr, oparg);
81 break;
Jakub Jelinek4732efb2005-09-06 15:16:25 -070082 default:
83 ret = -ENOSYS;
84 }
85
86 dec_preempt_count();
87
88 if (!ret) {
89 switch (cmp) {
90 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
91 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
92 case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
93 case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
94 case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
95 case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
96 default: ret = -ENOSYS;
97 }
98 }
99 return ret;
100}
101
102#endif
103#endif