.. | .. |
---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
---|
1 | 2 | /* |
---|
2 | 3 | * Atomic futex routines |
---|
3 | 4 | * |
---|
4 | 5 | * Based on the PowerPC implementataion |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | 6 | * |
---|
10 | 7 | * Copyright (C) 2013 TangoTec Ltd. |
---|
11 | 8 | * |
---|
.. | .. |
---|
15 | 12 | #ifndef _ASM_XTENSA_FUTEX_H |
---|
16 | 13 | #define _ASM_XTENSA_FUTEX_H |
---|
17 | 14 | |
---|
18 | | -#ifdef __KERNEL__ |
---|
19 | | - |
---|
20 | 15 | #include <linux/futex.h> |
---|
21 | 16 | #include <linux/uaccess.h> |
---|
22 | 17 | #include <linux/errno.h> |
---|
23 | 18 | |
---|
24 | | -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ |
---|
| 19 | +#if XCHAL_HAVE_EXCLUSIVE |
---|
| 20 | +#define __futex_atomic_op(insn, ret, old, uaddr, arg) \ |
---|
25 | 21 | __asm__ __volatile( \ |
---|
26 | | - "1: l32i %0, %2, 0\n" \ |
---|
| 22 | + "1: l32ex %[oldval], %[addr]\n" \ |
---|
27 | 23 | insn "\n" \ |
---|
28 | | - " wsr %0, scompare1\n" \ |
---|
29 | | - "2: s32c1i %1, %2, 0\n" \ |
---|
30 | | - " bne %1, %0, 1b\n" \ |
---|
31 | | - " movi %1, 0\n" \ |
---|
| 24 | + "2: s32ex %[newval], %[addr]\n" \ |
---|
| 25 | + " getex %[newval]\n" \ |
---|
| 26 | + " beqz %[newval], 1b\n" \ |
---|
| 27 | + " movi %[newval], 0\n" \ |
---|
32 | 28 | "3:\n" \ |
---|
33 | 29 | " .section .fixup,\"ax\"\n" \ |
---|
34 | 30 | " .align 4\n" \ |
---|
35 | | - "4: .long 3b\n" \ |
---|
36 | | - "5: l32r %0, 4b\n" \ |
---|
37 | | - " movi %1, %3\n" \ |
---|
38 | | - " jx %0\n" \ |
---|
| 31 | + " .literal_position\n" \ |
---|
| 32 | + "5: movi %[oldval], 3b\n" \ |
---|
| 33 | + " movi %[newval], %[fault]\n" \ |
---|
| 34 | + " jx %[oldval]\n" \ |
---|
39 | 35 | " .previous\n" \ |
---|
40 | 36 | " .section __ex_table,\"a\"\n" \ |
---|
41 | | - " .long 1b,5b,2b,5b\n" \ |
---|
| 37 | + " .long 1b, 5b, 2b, 5b\n" \ |
---|
42 | 38 | " .previous\n" \ |
---|
43 | | - : "=&r" (oldval), "=&r" (ret) \ |
---|
44 | | - : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \ |
---|
| 39 | + : [oldval] "=&r" (old), [newval] "=&r" (ret) \ |
---|
| 40 | + : [addr] "r" (uaddr), [oparg] "r" (arg), \ |
---|
| 41 | + [fault] "I" (-EFAULT) \ |
---|
45 | 42 | : "memory") |
---|
| 43 | +#elif XCHAL_HAVE_S32C1I |
---|
| 44 | +#define __futex_atomic_op(insn, ret, old, uaddr, arg) \ |
---|
| 45 | + __asm__ __volatile( \ |
---|
| 46 | + "1: l32i %[oldval], %[mem]\n" \ |
---|
| 47 | + insn "\n" \ |
---|
| 48 | + " wsr %[oldval], scompare1\n" \ |
---|
| 49 | + "2: s32c1i %[newval], %[mem]\n" \ |
---|
| 50 | + " bne %[newval], %[oldval], 1b\n" \ |
---|
| 51 | + " movi %[newval], 0\n" \ |
---|
| 52 | + "3:\n" \ |
---|
| 53 | + " .section .fixup,\"ax\"\n" \ |
---|
| 54 | + " .align 4\n" \ |
---|
| 55 | + " .literal_position\n" \ |
---|
| 56 | + "5: movi %[oldval], 3b\n" \ |
---|
| 57 | + " movi %[newval], %[fault]\n" \ |
---|
| 58 | + " jx %[oldval]\n" \ |
---|
| 59 | + " .previous\n" \ |
---|
| 60 | + " .section __ex_table,\"a\"\n" \ |
---|
| 61 | + " .long 1b, 5b, 2b, 5b\n" \ |
---|
| 62 | + " .previous\n" \ |
---|
| 63 | + : [oldval] "=&r" (old), [newval] "=&r" (ret), \ |
---|
| 64 | + [mem] "+m" (*(uaddr)) \ |
---|
| 65 | + : [oparg] "r" (arg), [fault] "I" (-EFAULT) \ |
---|
| 66 | + : "memory") |
---|
| 67 | +#endif |
---|
46 | 68 | |
---|
47 | 69 | static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, |
---|
48 | 70 | u32 __user *uaddr) |
---|
49 | 71 | { |
---|
| 72 | +#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE |
---|
50 | 73 | int oldval = 0, ret; |
---|
51 | 74 | |
---|
52 | | -#if !XCHAL_HAVE_S32C1I |
---|
53 | | - return -ENOSYS; |
---|
54 | | -#endif |
---|
55 | | - |
---|
56 | | - pagefault_disable(); |
---|
| 75 | + if (!access_ok(uaddr, sizeof(u32))) |
---|
| 76 | + return -EFAULT; |
---|
57 | 77 | |
---|
58 | 78 | switch (op) { |
---|
59 | 79 | case FUTEX_OP_SET: |
---|
60 | | - __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg); |
---|
| 80 | + __futex_atomic_op("mov %[newval], %[oparg]", |
---|
| 81 | + ret, oldval, uaddr, oparg); |
---|
61 | 82 | break; |
---|
62 | 83 | case FUTEX_OP_ADD: |
---|
63 | | - __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr, |
---|
64 | | - oparg); |
---|
| 84 | + __futex_atomic_op("add %[newval], %[oldval], %[oparg]", |
---|
| 85 | + ret, oldval, uaddr, oparg); |
---|
65 | 86 | break; |
---|
66 | 87 | case FUTEX_OP_OR: |
---|
67 | | - __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr, |
---|
68 | | - oparg); |
---|
| 88 | + __futex_atomic_op("or %[newval], %[oldval], %[oparg]", |
---|
| 89 | + ret, oldval, uaddr, oparg); |
---|
69 | 90 | break; |
---|
70 | 91 | case FUTEX_OP_ANDN: |
---|
71 | | - __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr, |
---|
72 | | - ~oparg); |
---|
| 92 | + __futex_atomic_op("and %[newval], %[oldval], %[oparg]", |
---|
| 93 | + ret, oldval, uaddr, ~oparg); |
---|
73 | 94 | break; |
---|
74 | 95 | case FUTEX_OP_XOR: |
---|
75 | | - __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr, |
---|
76 | | - oparg); |
---|
| 96 | + __futex_atomic_op("xor %[newval], %[oldval], %[oparg]", |
---|
| 97 | + ret, oldval, uaddr, oparg); |
---|
77 | 98 | break; |
---|
78 | 99 | default: |
---|
79 | 100 | ret = -ENOSYS; |
---|
80 | 101 | } |
---|
81 | 102 | |
---|
82 | | - pagefault_enable(); |
---|
83 | | - |
---|
84 | 103 | if (!ret) |
---|
85 | 104 | *oval = oldval; |
---|
86 | 105 | |
---|
87 | 106 | return ret; |
---|
| 107 | +#else |
---|
| 108 | + return -ENOSYS; |
---|
| 109 | +#endif |
---|
88 | 110 | } |
---|
89 | 111 | |
---|
90 | 112 | static inline int |
---|
91 | 113 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, |
---|
92 | 114 | u32 oldval, u32 newval) |
---|
93 | 115 | { |
---|
| 116 | +#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE |
---|
| 117 | + unsigned long tmp; |
---|
94 | 118 | int ret = 0; |
---|
95 | 119 | |
---|
96 | | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) |
---|
| 120 | + if (!access_ok(uaddr, sizeof(u32))) |
---|
97 | 121 | return -EFAULT; |
---|
98 | | - |
---|
99 | | -#if !XCHAL_HAVE_S32C1I |
---|
100 | | - return -ENOSYS; |
---|
101 | | -#endif |
---|
102 | 122 | |
---|
103 | 123 | __asm__ __volatile__ ( |
---|
104 | 124 | " # futex_atomic_cmpxchg_inatomic\n" |
---|
105 | | - " wsr %5, scompare1\n" |
---|
106 | | - "1: s32c1i %1, %4, 0\n" |
---|
107 | | - " s32i %1, %6, 0\n" |
---|
| 125 | +#if XCHAL_HAVE_EXCLUSIVE |
---|
| 126 | + "1: l32ex %[tmp], %[addr]\n" |
---|
| 127 | + " s32i %[tmp], %[uval], 0\n" |
---|
| 128 | + " bne %[tmp], %[oldval], 2f\n" |
---|
| 129 | + " mov %[tmp], %[newval]\n" |
---|
| 130 | + "3: s32ex %[tmp], %[addr]\n" |
---|
| 131 | + " getex %[tmp]\n" |
---|
| 132 | + " beqz %[tmp], 1b\n" |
---|
| 133 | +#elif XCHAL_HAVE_S32C1I |
---|
| 134 | + " wsr %[oldval], scompare1\n" |
---|
| 135 | + "1: s32c1i %[newval], %[addr], 0\n" |
---|
| 136 | + " s32i %[newval], %[uval], 0\n" |
---|
| 137 | +#endif |
---|
108 | 138 | "2:\n" |
---|
109 | 139 | " .section .fixup,\"ax\"\n" |
---|
110 | 140 | " .align 4\n" |
---|
111 | | - "3: .long 2b\n" |
---|
112 | | - "4: l32r %1, 3b\n" |
---|
113 | | - " movi %0, %7\n" |
---|
114 | | - " jx %1\n" |
---|
| 141 | + " .literal_position\n" |
---|
| 142 | + "4: movi %[tmp], 2b\n" |
---|
| 143 | + " movi %[ret], %[fault]\n" |
---|
| 144 | + " jx %[tmp]\n" |
---|
115 | 145 | " .previous\n" |
---|
116 | 146 | " .section __ex_table,\"a\"\n" |
---|
117 | | - " .long 1b,4b\n" |
---|
| 147 | + " .long 1b, 4b\n" |
---|
| 148 | +#if XCHAL_HAVE_EXCLUSIVE |
---|
| 149 | + " .long 3b, 4b\n" |
---|
| 150 | +#endif |
---|
118 | 151 | " .previous\n" |
---|
119 | | - : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval) |
---|
120 | | - : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT) |
---|
| 152 | + : [ret] "+r" (ret), [newval] "+r" (newval), [tmp] "=&r" (tmp) |
---|
| 153 | + : [addr] "r" (uaddr), [oldval] "r" (oldval), [uval] "r" (uval), |
---|
| 154 | + [fault] "I" (-EFAULT) |
---|
121 | 155 | : "memory"); |
---|
122 | 156 | |
---|
123 | 157 | return ret; |
---|
| 158 | +#else |
---|
| 159 | + return -ENOSYS; |
---|
| 160 | +#endif |
---|
124 | 161 | } |
---|
125 | 162 | |
---|
126 | | -#endif /* __KERNEL__ */ |
---|
127 | 163 | #endif /* _ASM_XTENSA_FUTEX_H */ |
---|