1 /* 2 * User space memory access functions for Nios II 3 * 4 * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch> 5 * Copyright (C) 2009, Wind River Systems Inc 6 * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12 13 #ifndef _ASM_NIOS2_UACCESS_H 14 #define _ASM_NIOS2_UACCESS_H 15 16 #include <linux/string.h> 17 18 #include <asm/page.h> 19 20 #include <asm/extable.h> 21 #include <asm-generic/access_ok.h> 22 23 # define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" 24 25 /* 26 * Zero Userspace 27 */ 28 29 static inline unsigned long __must_check __clear_user(void __user *to, 30 unsigned long n) 31 { 32 __asm__ __volatile__ ( 33 "1: stb zero, 0(%1)\n" 34 " addi %0, %0, -1\n" 35 " addi %1, %1, 1\n" 36 " bne %0, zero, 1b\n" 37 "2:\n" 38 __EX_TABLE_SECTION 39 ".word 1b, 2b\n" 40 ".previous\n" 41 : "=r" (n), "=r" (to) 42 : "0" (n), "1" (to) 43 ); 44 45 return n; 46 } 47 48 static inline unsigned long __must_check clear_user(void __user *to, 49 unsigned long n) 50 { 51 if (!access_ok(to, n)) 52 return n; 53 return __clear_user(to, n); 54 } 55 56 extern unsigned long 57 raw_copy_from_user(void *to, const void __user *from, unsigned long n); 58 extern unsigned long 59 raw_copy_to_user(void __user *to, const void *from, unsigned long n); 60 #define INLINE_COPY_USER 61 62 extern long strncpy_from_user(char *__to, const char __user *__from, 63 long __len); 64 extern __must_check long strnlen_user(const char __user *s, long n); 65 66 /* Optimized macros */ 67 #define __get_user_asm(val, insn, addr, err) \ 68 { \ 69 unsigned long __gu_val; \ 70 __asm__ __volatile__( \ 71 " movi %0, %3\n" \ 72 "1: " insn " %1, 0(%2)\n" \ 73 " movi %0, 0\n" \ 74 "2:\n" \ 75 " .section __ex_table,\"a\"\n" \ 76 " .word 1b, 2b\n" \ 77 " .previous" \ 78 : "=&r" (err), "=r" (__gu_val) \ 79 : "r" (addr), "i" (-EFAULT)); \ 80 val = (__force __typeof__(*(addr)))__gu_val; \ 81 } 82 83 extern void __get_user_unknown(void); 84 85 #define __get_user_8(val, ptr, err) do { \ 86 u64 __val = 0; \ 87 err = 0; \ 88 if (raw_copy_from_user(&(__val), ptr, sizeof(val))) { \ 89 err = -EFAULT; \ 90 } else { \ 91 val = (typeof(val))(typeof((val) - (val)))__val; \ 92 } \ 93 } while (0) 94 95 #define __get_user_common(val, size, ptr, err) \ 96 do { \ 97 switch (size) { \ 98 case 1: \ 99 __get_user_asm(val, "ldbu", ptr, err); \ 100 break; \ 101 case 2: \ 102 __get_user_asm(val, "ldhu", ptr, err); \ 103 break; \ 104 case 4: \ 105 __get_user_asm(val, "ldw", ptr, err); \ 106 break; \ 107 case 8: \ 108 __get_user_8(val, ptr, err); \ 109 break; \ 110 default: \ 111 __get_user_unknown(); \ 112 break; \ 113 } \ 114 } while (0) 115 116 #define __get_user(x, ptr) \ 117 ({ \ 118 long __gu_err = -EFAULT; \ 119 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 120 __get_user_common(x, sizeof(*(ptr)), __gu_ptr, __gu_err); \ 121 __gu_err; \ 122 }) 123 124 #define get_user(x, ptr) \ 125 ({ \ 126 long __gu_err = -EFAULT; \ 127 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 128 if (access_ok( __gu_ptr, sizeof(*__gu_ptr))) \ 129 __get_user_common(x, sizeof(*__gu_ptr), \ 130 __gu_ptr, __gu_err); \ 131 __gu_err; \ 132 }) 133 134 #define __put_user_asm(val, insn, ptr, err) \ 135 { \ 136 __asm__ __volatile__( \ 137 " movi %0, %3\n" \ 138 "1: " insn " %1, 0(%2)\n" \ 139 " movi %0, 0\n" \ 140 "2:\n" \ 141 " .section __ex_table,\"a\"\n" \ 142 " .word 1b, 2b\n" \ 143 " .previous\n" \ 144 : "=&r" (err) \ 145 : "r" (val), "r" (ptr), "i" (-EFAULT)); \ 146 } 147 148 #define __put_user_common(__pu_val, __pu_ptr) \ 149 ({ \ 150 long __pu_err = -EFAULT; \ 151 switch (sizeof(*__pu_ptr)) { \ 152 case 1: \ 153 __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ 154 break; \ 155 case 2: \ 156 __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ 157 break; \ 158 case 4: \ 159 __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ 160 break; \ 161 default: \ 162 /* XXX: This looks wrong... */ \ 163 __pu_err = 0; \ 164 if (__copy_to_user(__pu_ptr, &(__pu_val), \ 165 sizeof(*__pu_ptr))) \ 166 __pu_err = -EFAULT; \ 167 break; \ 168 } \ 169 __pu_err; \ 170 }) 171 172 #define __put_user(x, ptr) \ 173 ({ \ 174 auto __pu_ptr = (ptr); \ 175 auto __pu_val = (typeof(*__pu_ptr))(x); \ 176 __put_user_common(__pu_val, __pu_ptr); \ 177 }) 178 179 #define put_user(x, ptr) \ 180 ({ \ 181 auto __pu_ptr = (ptr); \ 182 auto __pu_val = (typeof(*__pu_ptr))(x); \ 183 access_ok(__pu_ptr, sizeof(*__pu_ptr)) ? \ 184 __put_user_common(__pu_val, __pu_ptr) : \ 185 -EFAULT; \ 186 }) 187 188 #endif /* _ASM_NIOS2_UACCESS_H */ 189