|
@@ -168,3 +168,81 @@ struct __large_struct { unsigned long buf[100]; };
|
|
|
/* Unfortunately, we can't get an unaligned access trap for the sub-word
|
|
|
load, so we have to do a general unaligned operation. */
|
|
|
|
|
|
+#define __get_user_16(addr) \
|
|
|
+{ \
|
|
|
+ long __gu_tmp; \
|
|
|
+ __asm__("1: ldq_u %0,0(%3)\n" \
|
|
|
+ "2: ldq_u %1,1(%3)\n" \
|
|
|
+ " extwl %0,%3,%0\n" \
|
|
|
+ " extwh %1,%3,%1\n" \
|
|
|
+ " or %0,%1,%0\n" \
|
|
|
+ "3:\n" \
|
|
|
+ ".section __ex_table,\"a\"\n" \
|
|
|
+ " .long 1b - .\n" \
|
|
|
+ " lda %0, 3b-1b(%2)\n" \
|
|
|
+ " .long 2b - .\n" \
|
|
|
+ " lda %0, 3b-2b(%2)\n" \
|
|
|
+ ".previous" \
|
|
|
+ : "=&r"(__gu_val), "=&r"(__gu_tmp), "=r"(__gu_err) \
|
|
|
+ : "r"(addr), "2"(__gu_err)); \
|
|
|
+}
|
|
|
+
|
|
|
+#define __get_user_8(addr) \
|
|
|
+ __asm__("1: ldq_u %0,0(%2)\n" \
|
|
|
+ " extbl %0,%2,%0\n" \
|
|
|
+ "2:\n" \
|
|
|
+ ".section __ex_table,\"a\"\n" \
|
|
|
+ " .long 1b - .\n" \
|
|
|
+ " lda %0, 2b-1b(%1)\n" \
|
|
|
+ ".previous" \
|
|
|
+ : "=&r"(__gu_val), "=r"(__gu_err) \
|
|
|
+ : "r"(addr), "1"(__gu_err))
|
|
|
+#endif
|
|
|
+
|
|
|
+extern void __put_user_unknown(void);
|
|
|
+
|
|
|
+#define __put_user_nocheck(x,ptr,size) \
|
|
|
+({ \
|
|
|
+ long __pu_err = 0; \
|
|
|
+ __chk_user_ptr(ptr); \
|
|
|
+ switch (size) { \
|
|
|
+ case 1: __put_user_8(x,ptr); break; \
|
|
|
+ case 2: __put_user_16(x,ptr); break; \
|
|
|
+ case 4: __put_user_32(x,ptr); break; \
|
|
|
+ case 8: __put_user_64(x,ptr); break; \
|
|
|
+ default: __put_user_unknown(); break; \
|
|
|
+ } \
|
|
|
+ __pu_err; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __put_user_check(x,ptr,size,segment) \
|
|
|
+({ \
|
|
|
+ long __pu_err = -EFAULT; \
|
|
|
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
|
|
|
+ if (__access_ok((unsigned long)__pu_addr,size,segment)) { \
|
|
|
+ __pu_err = 0; \
|
|
|
+ switch (size) { \
|
|
|
+ case 1: __put_user_8(x,__pu_addr); break; \
|
|
|
+ case 2: __put_user_16(x,__pu_addr); break; \
|
|
|
+ case 4: __put_user_32(x,__pu_addr); break; \
|
|
|
+ case 8: __put_user_64(x,__pu_addr); break; \
|
|
|
+ default: __put_user_unknown(); break; \
|
|
|
+ } \
|
|
|
+ } \
|
|
|
+ __pu_err; \
|
|
|
+})
|
|
|
+
|
|
|
+/*
|
|
|
+ * The "__put_user_xx()" macros tell gcc they read from memory
|
|
|
+ * instead of writing: this is because they do not write to
|
|
|
+ * any memory gcc knows about, so there are no aliasing issues
|
|
|
+ */
|
|
|
+#define __put_user_64(x,addr) \
|
|
|
+__asm__ __volatile__("1: stq %r2,%1\n" \
|
|
|
+ "2:\n" \
|
|
|
+ ".section __ex_table,\"a\"\n" \
|
|
|
+ " .long 1b - .\n" \
|
|
|
+ " lda $31,2b-1b(%0)\n" \
|
|
|
+ ".previous" \
|
|
|
+ : "=r"(__pu_err) \
|
|
|
+ : "m" (__m(addr)), "rJ" (x), "0"(__pu_err))
|