summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaruch Siach <baruch@tkos.co.il>2013-11-18 06:46:43 +0200
committerChris Zankel <chris@zankel.net>2014-01-14 10:19:51 -0800
commit220c062688c31bbf992921fca172ddd1e609f8f6 (patch)
tree1dcc29d05ab14df393f414b20bc9f29b28a1e137
parenta6e16b9aaf0df4b1de8853cad97f387ade9fa8f5 (diff)
downloadop-kernel-dev-220c062688c31bbf992921fca172ddd1e609f8f6.zip
op-kernel-dev-220c062688c31bbf992921fca172ddd1e609f8f6.tar.gz
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>
-rw-r--r--arch/xtensa/include/asm/Kbuild1
-rw-r--r--arch/xtensa/include/asm/futex.h147
2 files changed, 147 insertions, 1 deletions
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index 228d6ae..5851db2 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -8,7 +8,6 @@ generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
generic-y += fcntl.h
-generic-y += futex.h
generic-y += hardirq.h
generic-y += ioctl.h
generic-y += irq_regs.h
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
new file mode 100644
index 0000000..b39531b
--- /dev/null
+++ b/arch/xtensa/include/asm/futex.h
@@ -0,0 +1,147 @@
+/*
+ * Atomic futex routines
+ *
+ * Based on the PowerPC implementataion
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2013 TangoTec Ltd.
+ *
+ * Baruch Siach <baruch@tkos.co.il>
+ */
+
+#ifndef _ASM_XTENSA_FUTEX_H
+#define _ASM_XTENSA_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+ __asm__ __volatile( \
+ "1: l32i %0, %2, 0\n" \
+ insn "\n" \
+ " wsr %0, scompare1\n" \
+ "2: s32c1i %1, %2, 0\n" \
+ " bne %1, %0, 1b\n" \
+ " movi %1, 0\n" \
+ "3:\n" \
+ " .section .fixup,\"ax\"\n" \
+ " .align 4\n" \
+ "4: .long 3b\n" \
+ "5: l32r %0, 4b\n" \
+ " movi %1, %3\n" \
+ " jx %0\n" \
+ " .previous\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .long 1b,5b,2b,5b\n" \
+ " .previous\n" \
+ : "=&r" (oldval), "=&r" (ret) \
+ : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \
+ : "memory")
+
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+ return -EFAULT;
+
+#if !XCHAL_HAVE_S32C1I
+ return -ENOSYS;
+#endif
+
+ pagefault_disable();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
+ oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
+ oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
+ ~oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
+ oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ pagefault_enable();
+
+ if (ret)
+ return ret;
+
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
+ case FUTEX_OP_CMP_NE: return (oldval != cmparg);
+ case FUTEX_OP_CMP_LT: return (oldval < cmparg);
+ case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
+ case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
+ case FUTEX_OP_CMP_GT: return (oldval > cmparg);
+ }
+
+ return -ENOSYS;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ int ret = 0;
+ u32 prev;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+ return -EFAULT;
+
+#if !XCHAL_HAVE_S32C1I
+ return -ENOSYS;
+#endif
+
+ __asm__ __volatile__ (
+ " # futex_atomic_cmpxchg_inatomic\n"
+ "1: l32i %1, %3, 0\n"
+ " mov %0, %5\n"
+ " wsr %1, scompare1\n"
+ "2: s32c1i %0, %3, 0\n"
+ "3:\n"
+ " .section .fixup,\"ax\"\n"
+ " .align 4\n"
+ "4: .long 3b\n"
+ "5: l32r %1, 4b\n"
+ " movi %0, %6\n"
+ " jx %1\n"
+ " .previous\n"
+ " .section __ex_table,\"a\"\n"
+ " .long 1b,5b,2b,5b\n"
+ " .previous\n"
+ : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
+ : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
+ : "memory");
+
+ *uval = prev;
+ return ret;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_XTENSA_FUTEX_H */
OpenPOWER on IntegriCloud