1 #ifndef __ASM_SH_FUTEX_H 2 #define __ASM_SH_FUTEX_H 3 4 #ifdef __KERNEL__ 5 6 #include <linux/futex.h> 7 #include <linux/uaccess.h> 8 #include <asm/errno.h> 9 10 #if !defined(CONFIG_SMP) 11 #include <asm/futex-irq.h> 12 #elif defined(CONFIG_CPU_J2) 13 #include <asm/futex-cas.h> 14 #elif defined(CONFIG_CPU_SH4A) 15 #include <asm/futex-llsc.h> 16 #else 17 #error SMP not supported on this configuration. 18 #endif 19 20 static inline int 21 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, 22 u32 oldval, u32 newval) 23 { 24 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 25 return -EFAULT; 26 27 return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); 28 } 29 30 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) 31 { 32 int op = (encoded_op >> 28) & 7; 33 int cmp = (encoded_op >> 24) & 15; 34 u32 oparg = (encoded_op << 8) >> 20; 35 u32 cmparg = (encoded_op << 20) >> 20; 36 u32 oldval, newval, prev; 37 int ret; 38 39 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 40 oparg = 1 << oparg; 41 42 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) 43 return -EFAULT; 44 45 pagefault_disable(); 46 47 do { 48 if (op == FUTEX_OP_SET) 49 ret = oldval = 0; 50 else 51 ret = get_user(oldval, uaddr); 52 53 if (ret) break; 54 55 switch (op) { 56 case FUTEX_OP_SET: 57 newval = oparg; 58 break; 59 case FUTEX_OP_ADD: 60 newval = oldval + oparg; 61 break; 62 case FUTEX_OP_OR: 63 newval = oldval | oparg; 64 break; 65 case FUTEX_OP_ANDN: 66 newval = oldval & ~oparg; 67 break; 68 case FUTEX_OP_XOR: 69 newval = oldval ^ oparg; 70 break; 71 default: 72 ret = -ENOSYS; 73 break; 74 } 75 76 if (ret) break; 77 78 ret = futex_atomic_cmpxchg_inatomic(&prev, uaddr, oldval, newval); 79 } while (!ret && prev != oldval); 80 81 pagefault_enable(); 82 83 if (!ret) { 84 switch (cmp) { 85 case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; 86 case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; 87 case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break; 88 case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break; 89 case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break; 90 case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break; 91 default: ret = -ENOSYS; 92 } 93 } 94 95 return ret; 96 } 97 98 #endif /* __KERNEL__ */ 99 #endif /* __ASM_SH_FUTEX_H */ 100