|
@@ -213,3 +213,110 @@ extern int __put_user_bad(void);
|
|
|
break; \
|
|
|
case 4: \
|
|
|
__get_user_asm("w", __gu_val, __gu_addr, \
|
|
|
+ __gu_err); \
|
|
|
+ break; \
|
|
|
+ default: \
|
|
|
+ __gu_err = __get_user_bad(); \
|
|
|
+ break; \
|
|
|
+ } \
|
|
|
+ } else { \
|
|
|
+ __gu_err = -EFAULT; \
|
|
|
+ } \
|
|
|
+ x = (typeof(*(ptr)))__gu_val; \
|
|
|
+ __gu_err; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __get_user_asm(suffix, __gu_val, ptr, __gu_err) \
|
|
|
+ asm volatile( \
|
|
|
+ "1: ld." suffix " %1, %3 \n" \
|
|
|
+ "2: \n" \
|
|
|
+ " .subsection 1 \n" \
|
|
|
+ "3: mov %0, %4 \n" \
|
|
|
+ " rjmp 2b \n" \
|
|
|
+ " .subsection 0 \n" \
|
|
|
+ " .section __ex_table, \"a\" \n" \
|
|
|
+ " .long 1b, 3b \n" \
|
|
|
+ " .previous \n" \
|
|
|
+ : "=r"(__gu_err), "=r"(__gu_val) \
|
|
|
+ : "0"(__gu_err), "m"(*(ptr)), "i"(-EFAULT))
|
|
|
+
|
|
|
+#define __put_user_nocheck(x, ptr, size) \
|
|
|
+({ \
|
|
|
+ typeof(*(ptr)) __pu_val; \
|
|
|
+ int __pu_err = 0; \
|
|
|
+ \
|
|
|
+ __pu_val = (x); \
|
|
|
+ switch (size) { \
|
|
|
+ case 1: __put_user_asm("b", ptr, __pu_val, __pu_err); break; \
|
|
|
+ case 2: __put_user_asm("h", ptr, __pu_val, __pu_err); break; \
|
|
|
+ case 4: __put_user_asm("w", ptr, __pu_val, __pu_err); break; \
|
|
|
+ case 8: __put_user_asm("d", ptr, __pu_val, __pu_err); break; \
|
|
|
+ default: __pu_err = __put_user_bad(); break; \
|
|
|
+ } \
|
|
|
+ __pu_err; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __put_user_check(x, ptr, size) \
|
|
|
+({ \
|
|
|
+ typeof(*(ptr)) __pu_val; \
|
|
|
+ typeof(*(ptr)) __user *__pu_addr = (ptr); \
|
|
|
+ int __pu_err = 0; \
|
|
|
+ \
|
|
|
+ __pu_val = (x); \
|
|
|
+ if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \
|
|
|
+ switch (size) { \
|
|
|
+ case 1: \
|
|
|
+ __put_user_asm("b", __pu_addr, __pu_val, \
|
|
|
+ __pu_err); \
|
|
|
+ break; \
|
|
|
+ case 2: \
|
|
|
+ __put_user_asm("h", __pu_addr, __pu_val, \
|
|
|
+ __pu_err); \
|
|
|
+ break; \
|
|
|
+ case 4: \
|
|
|
+ __put_user_asm("w", __pu_addr, __pu_val, \
|
|
|
+ __pu_err); \
|
|
|
+ break; \
|
|
|
+ case 8: \
|
|
|
+ __put_user_asm("d", __pu_addr, __pu_val, \
|
|
|
+ __pu_err); \
|
|
|
+ break; \
|
|
|
+ default: \
|
|
|
+ __pu_err = __put_user_bad(); \
|
|
|
+ break; \
|
|
|
+ } \
|
|
|
+ } else { \
|
|
|
+ __pu_err = -EFAULT; \
|
|
|
+ } \
|
|
|
+ __pu_err; \
|
|
|
+})
|
|
|
+
|
|
|
+#define __put_user_asm(suffix, ptr, __pu_val, __gu_err) \
|
|
|
+ asm volatile( \
|
|
|
+ "1: st." suffix " %1, %3 \n" \
|
|
|
+ "2: \n" \
|
|
|
+ " .subsection 1 \n" \
|
|
|
+ "3: mov %0, %4 \n" \
|
|
|
+ " rjmp 2b \n" \
|
|
|
+ " .subsection 0 \n" \
|
|
|
+ " .section __ex_table, \"a\" \n" \
|
|
|
+ " .long 1b, 3b \n" \
|
|
|
+ " .previous \n" \
|
|
|
+ : "=r"(__gu_err), "=m"(*(ptr)) \
|
|
|
+ : "0"(__gu_err), "r"(__pu_val), "i"(-EFAULT))
|
|
|
+
|
|
|
+extern __kernel_size_t clear_user(void __user *addr, __kernel_size_t size);
|
|
|
+extern __kernel_size_t __clear_user(void __user *addr, __kernel_size_t size);
|
|
|
+
|
|
|
+extern long strncpy_from_user(char *dst, const char __user *src, long count);
|
|
|
+extern long __strncpy_from_user(char *dst, const char __user *src, long count);
|
|
|
+
|
|
|
+extern long strnlen_user(const char __user *__s, long __n);
|
|
|
+extern long __strnlen_user(const char __user *__s, long __n);
|
|
|
+
|
|
|
+#define strlen_user(s) strnlen_user(s, ~0UL >> 1)
|
|
|
+
|
|
|
+struct exception_table_entry
|
|
|
+{
|
|
|
+ unsigned long insn, fixup;
|
|
|
+};
|