| .. | .. |
|---|
| 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 */ |
|---|