Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xtensa: implement robust futex atomic uaccess ops

This enables the set_robust_list(2) system call.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Chris Zankel <chris@zankel.net>

authored by

Baruch Siach and committed by
Chris Zankel
220c0626 a6e16b9a

+147 -1
-1
arch/xtensa/include/asm/Kbuild
··· 8 8 generic-y += errno.h 9 9 generic-y += exec.h 10 10 generic-y += fcntl.h 11 - generic-y += futex.h 12 11 generic-y += hardirq.h 13 12 generic-y += ioctl.h 14 13 generic-y += irq_regs.h
+147
arch/xtensa/include/asm/futex.h
··· 1 + /* 2 + * Atomic futex routines 3 + * 4 + * 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 + * 10 + * Copyright (C) 2013 TangoTec Ltd. 11 + * 12 + * Baruch Siach <baruch@tkos.co.il> 13 + */ 14 + 15 + #ifndef _ASM_XTENSA_FUTEX_H 16 + #define _ASM_XTENSA_FUTEX_H 17 + 18 + #ifdef __KERNEL__ 19 + 20 + #include <linux/futex.h> 21 + #include <linux/uaccess.h> 22 + #include <linux/errno.h> 23 + 24 + #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 25 + __asm__ __volatile( \ 26 + "1: l32i %0, %2, 0\n" \ 27 + 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" \ 32 + "3:\n" \ 33 + " .section .fixup,\"ax\"\n" \ 34 + " .align 4\n" \ 35 + "4: .long 3b\n" \ 36 + "5: l32r %0, 4b\n" \ 37 + " movi %1, %3\n" \ 38 + " jx %0\n" \ 39 + " .previous\n" \ 40 + " .section __ex_table,\"a\"\n" \ 41 + " .long 1b,5b,2b,5b\n" \ 42 + " .previous\n" \ 43 + : "=&r" (oldval), "=&r" (ret) \ 44 + : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \ 45 + : "memory") 46 + 47 + static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) 48 + { 49 + int op = (encoded_op >> 28) & 7; 50 + int cmp = (encoded_op >> 24) & 15; 51 + int oparg = (encoded_op << 8) >> 20; 52 + int cmparg = (encoded_op << 20) >> 20; 53 + int oldval = 0, ret; 54 + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 55 + oparg = 1 << oparg; 56 + 57 + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 58 + return -EFAULT; 59 + 60 + #if !XCHAL_HAVE_S32C1I 61 + return -ENOSYS; 62 + #endif 63 + 64 + pagefault_disable(); 65 + 66 + switch (op) { 67 + case FUTEX_OP_SET: 68 + __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg); 69 + break; 70 + case FUTEX_OP_ADD: 71 + __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr, 72 + oparg); 73 + break; 74 + case FUTEX_OP_OR: 75 + __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr, 76 + oparg); 77 + break; 78 + case FUTEX_OP_ANDN: 79 + __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr, 80 + ~oparg); 81 + break; 82 + case FUTEX_OP_XOR: 83 + __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr, 84 + oparg); 85 + break; 86 + default: 87 + ret = -ENOSYS; 88 + } 89 + 90 + pagefault_enable(); 91 + 92 + if (ret) 93 + return ret; 94 + 95 + switch (cmp) { 96 + case FUTEX_OP_CMP_EQ: return (oldval == cmparg); 97 + case FUTEX_OP_CMP_NE: return (oldval != cmparg); 98 + case FUTEX_OP_CMP_LT: return (oldval < cmparg); 99 + case FUTEX_OP_CMP_GE: return (oldval >= cmparg); 100 + case FUTEX_OP_CMP_LE: return (oldval <= cmparg); 101 + case FUTEX_OP_CMP_GT: return (oldval > cmparg); 102 + } 103 + 104 + return -ENOSYS; 105 + } 106 + 107 + static inline int 108 + futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 109 + u32 oldval, u32 newval) 110 + { 111 + int ret = 0; 112 + u32 prev; 113 + 114 + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 115 + return -EFAULT; 116 + 117 + #if !XCHAL_HAVE_S32C1I 118 + return -ENOSYS; 119 + #endif 120 + 121 + __asm__ __volatile__ ( 122 + " # futex_atomic_cmpxchg_inatomic\n" 123 + "1: l32i %1, %3, 0\n" 124 + " mov %0, %5\n" 125 + " wsr %1, scompare1\n" 126 + "2: s32c1i %0, %3, 0\n" 127 + "3:\n" 128 + " .section .fixup,\"ax\"\n" 129 + " .align 4\n" 130 + "4: .long 3b\n" 131 + "5: l32r %1, 4b\n" 132 + " movi %0, %6\n" 133 + " jx %1\n" 134 + " .previous\n" 135 + " .section __ex_table,\"a\"\n" 136 + " .long 1b,5b,2b,5b\n" 137 + " .previous\n" 138 + : "+r" (ret), "=&r" (prev), "+m" (*uaddr) 139 + : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT) 140 + : "memory"); 141 + 142 + *uval = prev; 143 + return ret; 144 + } 145 + 146 + #endif /* __KERNEL__ */ 147 + #endif /* _ASM_XTENSA_FUTEX_H */