Merge tag 'audit-pr-20171113' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoor...
[sfrench/cifs-2.6.git] / arch / mips / include / asm / futex.h
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) 2006  Ralf Baechle (ralf@linux-mips.org)
7  */
8 #ifndef _ASM_FUTEX_H
9 #define _ASM_FUTEX_H
10
11 #ifdef __KERNEL__
12
13 #include <linux/futex.h>
14 #include <linux/uaccess.h>
15 #include <asm/asm-eva.h>
16 #include <asm/barrier.h>
17 #include <asm/compiler.h>
18 #include <asm/errno.h>
19 #include <asm/war.h>
20
21 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)              \
22 {                                                                       \
23         if (cpu_has_llsc && R10000_LLSC_WAR) {                          \
24                 __asm__ __volatile__(                                   \
25                 "       .set    push                            \n"     \
26                 "       .set    noat                            \n"     \
27                 "       .set    arch=r4000                      \n"     \
28                 "1:     ll      %1, %4  # __futex_atomic_op     \n"     \
29                 "       .set    mips0                           \n"     \
30                 "       " insn  "                               \n"     \
31                 "       .set    arch=r4000                      \n"     \
32                 "2:     sc      $1, %2                          \n"     \
33                 "       beqzl   $1, 1b                          \n"     \
34                 __WEAK_LLSC_MB                                          \
35                 "3:                                             \n"     \
36                 "       .insn                                   \n"     \
37                 "       .set    pop                             \n"     \
38                 "       .set    mips0                           \n"     \
39                 "       .section .fixup,\"ax\"                  \n"     \
40                 "4:     li      %0, %6                          \n"     \
41                 "       j       3b                              \n"     \
42                 "       .previous                               \n"     \
43                 "       .section __ex_table,\"a\"               \n"     \
44                 "       "__UA_ADDR "\t1b, 4b                    \n"     \
45                 "       "__UA_ADDR "\t2b, 4b                    \n"     \
46                 "       .previous                               \n"     \
47                 : "=r" (ret), "=&r" (oldval),                           \
48                   "=" GCC_OFF_SMALL_ASM() (*uaddr)                              \
49                 : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg),  \
50                   "i" (-EFAULT)                                         \
51                 : "memory");                                            \
52         } else if (cpu_has_llsc) {                                      \
53                 __asm__ __volatile__(                                   \
54                 "       .set    push                            \n"     \
55                 "       .set    noat                            \n"     \
56                 "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"     \
57                 "1:     "user_ll("%1", "%4")" # __futex_atomic_op\n"    \
58                 "       .set    mips0                           \n"     \
59                 "       " insn  "                               \n"     \
60                 "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"     \
61                 "2:     "user_sc("$1", "%2")"                   \n"     \
62                 "       beqz    $1, 1b                          \n"     \
63                 __WEAK_LLSC_MB                                          \
64                 "3:                                             \n"     \
65                 "       .insn                                   \n"     \
66                 "       .set    pop                             \n"     \
67                 "       .set    mips0                           \n"     \
68                 "       .section .fixup,\"ax\"                  \n"     \
69                 "4:     li      %0, %6                          \n"     \
70                 "       j       3b                              \n"     \
71                 "       .previous                               \n"     \
72                 "       .section __ex_table,\"a\"               \n"     \
73                 "       "__UA_ADDR "\t1b, 4b                    \n"     \
74                 "       "__UA_ADDR "\t2b, 4b                    \n"     \
75                 "       .previous                               \n"     \
76                 : "=r" (ret), "=&r" (oldval),                           \
77                   "=" GCC_OFF_SMALL_ASM() (*uaddr)                              \
78                 : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg),  \
79                   "i" (-EFAULT)                                         \
80                 : "memory");                                            \
81         } else                                                          \
82                 ret = -ENOSYS;                                          \
83 }
84
85 static inline int
86 arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
87 {
88         int oldval = 0, ret;
89
90         pagefault_disable();
91
92         switch (op) {
93         case FUTEX_OP_SET:
94                 __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg);
95                 break;
96
97         case FUTEX_OP_ADD:
98                 __futex_atomic_op("addu $1, %1, %z5",
99                                   ret, oldval, uaddr, oparg);
100                 break;
101         case FUTEX_OP_OR:
102                 __futex_atomic_op("or   $1, %1, %z5",
103                                   ret, oldval, uaddr, oparg);
104                 break;
105         case FUTEX_OP_ANDN:
106                 __futex_atomic_op("and  $1, %1, %z5",
107                                   ret, oldval, uaddr, ~oparg);
108                 break;
109         case FUTEX_OP_XOR:
110                 __futex_atomic_op("xor  $1, %1, %z5",
111                                   ret, oldval, uaddr, oparg);
112                 break;
113         default:
114                 ret = -ENOSYS;
115         }
116
117         pagefault_enable();
118
119         if (!ret)
120                 *oval = oldval;
121
122         return ret;
123 }
124
125 static inline int
126 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
127                               u32 oldval, u32 newval)
128 {
129         int ret = 0;
130         u32 val;
131
132         if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
133                 return -EFAULT;
134
135         if (cpu_has_llsc && R10000_LLSC_WAR) {
136                 __asm__ __volatile__(
137                 "# futex_atomic_cmpxchg_inatomic                        \n"
138                 "       .set    push                                    \n"
139                 "       .set    noat                                    \n"
140                 "       .set    arch=r4000                              \n"
141                 "1:     ll      %1, %3                                  \n"
142                 "       bne     %1, %z4, 3f                             \n"
143                 "       .set    mips0                                   \n"
144                 "       move    $1, %z5                                 \n"
145                 "       .set    arch=r4000                              \n"
146                 "2:     sc      $1, %2                                  \n"
147                 "       beqzl   $1, 1b                                  \n"
148                 __WEAK_LLSC_MB
149                 "3:                                                     \n"
150                 "       .insn                                           \n"
151                 "       .set    pop                                     \n"
152                 "       .section .fixup,\"ax\"                          \n"
153                 "4:     li      %0, %6                                  \n"
154                 "       j       3b                                      \n"
155                 "       .previous                                       \n"
156                 "       .section __ex_table,\"a\"                       \n"
157                 "       "__UA_ADDR "\t1b, 4b                            \n"
158                 "       "__UA_ADDR "\t2b, 4b                            \n"
159                 "       .previous                                       \n"
160                 : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
161                 : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
162                   "i" (-EFAULT)
163                 : "memory");
164         } else if (cpu_has_llsc) {
165                 __asm__ __volatile__(
166                 "# futex_atomic_cmpxchg_inatomic                        \n"
167                 "       .set    push                                    \n"
168                 "       .set    noat                                    \n"
169                 "       .set    "MIPS_ISA_ARCH_LEVEL"                   \n"
170                 "1:     "user_ll("%1", "%3")"                           \n"
171                 "       bne     %1, %z4, 3f                             \n"
172                 "       .set    mips0                                   \n"
173                 "       move    $1, %z5                                 \n"
174                 "       .set    "MIPS_ISA_ARCH_LEVEL"                   \n"
175                 "2:     "user_sc("$1", "%2")"                           \n"
176                 "       beqz    $1, 1b                                  \n"
177                 __WEAK_LLSC_MB
178                 "3:                                                     \n"
179                 "       .insn                                           \n"
180                 "       .set    pop                                     \n"
181                 "       .section .fixup,\"ax\"                          \n"
182                 "4:     li      %0, %6                                  \n"
183                 "       j       3b                                      \n"
184                 "       .previous                                       \n"
185                 "       .section __ex_table,\"a\"                       \n"
186                 "       "__UA_ADDR "\t1b, 4b                            \n"
187                 "       "__UA_ADDR "\t2b, 4b                            \n"
188                 "       .previous                                       \n"
189                 : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
190                 : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
191                   "i" (-EFAULT)
192                 : "memory");
193         } else
194                 return -ENOSYS;
195
196         *uval = val;
197         return ret;
198 }
199
200 #endif
201 #endif /* _ASM_FUTEX_H */