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/errno.h> 17 #include <linux/thread_info.h> 18 #include <linux/string.h> 19 20 #include <asm/page.h> 21 22 #define VERIFY_READ 0 23 #define VERIFY_WRITE 1 24 25 /* 26 * The exception table consists of pairs of addresses: the first is the 27 * address of an instruction that is allowed to fault, and the second is 28 * the address at which the program should continue. No registers are 29 * modified, so it is entirely up to the continuation code to figure out 30 * what to do. 31 * 32 * All the routines below use bits of fixup code that are out of line 33 * with the main instruction path. This means when everything is well, 34 * we don't even have to jump over them. Further, they do not intrude 35 * on our cache or tlb entries. 36 */ 37 struct exception_table_entry { 38 unsigned long insn; 39 unsigned long fixup; 40 }; 41 42 extern int fixup_exception(struct pt_regs *regs); 43 44 /* 45 * Segment stuff 46 */ 47 #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) 48 #define USER_DS MAKE_MM_SEG(0x80000000UL) 49 #define KERNEL_DS MAKE_MM_SEG(0) 50 51 #define get_ds() (KERNEL_DS) 52 53 #define get_fs() (current_thread_info()->addr_limit) 54 #define set_fs(seg) (current_thread_info()->addr_limit = (seg)) 55 56 #define segment_eq(a, b) ((a).seg == (b).seg) 57 58 #define __access_ok(addr, len) \ 59 (((signed long)(((long)get_fs().seg) & \ 60 ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0) 61 62 #define access_ok(type, addr, len) \ 63 likely(__access_ok((unsigned long)(addr), (unsigned long)(len))) 64 65 # define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" 66 67 /* 68 * Zero Userspace 69 */ 70 71 static inline unsigned long __must_check __clear_user(void __user *to, 72 unsigned long n) 73 { 74 __asm__ __volatile__ ( 75 "1: stb zero, 0(%1)\n" 76 " addi %0, %0, -1\n" 77 " addi %1, %1, 1\n" 78 " bne %0, zero, 1b\n" 79 "2:\n" 80 __EX_TABLE_SECTION 81 ".word 1b, 2b\n" 82 ".previous\n" 83 : "=r" (n), "=r" (to) 84 : "0" (n), "1" (to) 85 ); 86 87 return n; 88 } 89 90 static inline unsigned long __must_check clear_user(void __user *to, 91 unsigned long n) 92 { 93 if (!access_ok(VERIFY_WRITE, to, n)) 94 return n; 95 return __clear_user(to, n); 96 } 97 98 extern long __copy_from_user(void *to, const void __user *from, 99 unsigned long n); 100 extern long __copy_to_user(void __user *to, const void *from, unsigned long n); 101 102 static inline long copy_from_user(void *to, const void __user *from, 103 unsigned long n) 104 { 105 unsigned long res = n; 106 if (access_ok(VERIFY_READ, from, n)) 107 res = __copy_from_user(to, from, n); 108 if (unlikely(res)) 109 memset(to + (n - res), 0, res); 110 return res; 111 } 112 113 static inline long copy_to_user(void __user *to, const void *from, 114 unsigned long n) 115 { 116 if (!access_ok(VERIFY_WRITE, to, n)) 117 return n; 118 return __copy_to_user(to, from, n); 119 } 120 121 extern long strncpy_from_user(char *__to, const char __user *__from, 122 long __len); 123 extern long strnlen_user(const char __user *s, long n); 124 125 #define __copy_from_user_inatomic __copy_from_user 126 #define __copy_to_user_inatomic __copy_to_user 127 128 /* Optimized macros */ 129 #define __get_user_asm(val, insn, addr, err) \ 130 { \ 131 __asm__ __volatile__( \ 132 " movi %0, %3\n" \ 133 "1: " insn " %1, 0(%2)\n" \ 134 " movi %0, 0\n" \ 135 "2:\n" \ 136 " .section __ex_table,\"a\"\n" \ 137 " .word 1b, 2b\n" \ 138 " .previous" \ 139 : "=&r" (err), "=r" (val) \ 140 : "r" (addr), "i" (-EFAULT)); \ 141 } 142 143 #define __get_user_unknown(val, size, ptr, err) do { \ 144 err = 0; \ 145 if (__copy_from_user(&(val), ptr, size)) { \ 146 err = -EFAULT; \ 147 } \ 148 } while (0) 149 150 #define __get_user_common(val, size, ptr, err) \ 151 do { \ 152 switch (size) { \ 153 case 1: \ 154 __get_user_asm(val, "ldbu", ptr, err); \ 155 break; \ 156 case 2: \ 157 __get_user_asm(val, "ldhu", ptr, err); \ 158 break; \ 159 case 4: \ 160 __get_user_asm(val, "ldw", ptr, err); \ 161 break; \ 162 default: \ 163 __get_user_unknown(val, size, ptr, err); \ 164 break; \ 165 } \ 166 } while (0) 167 168 #define __get_user(x, ptr) \ 169 ({ \ 170 long __gu_err = -EFAULT; \ 171 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 172 unsigned long __gu_val = 0; \ 173 __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\ 174 (x) = (__force __typeof__(x))__gu_val; \ 175 __gu_err; \ 176 }) 177 178 #define get_user(x, ptr) \ 179 ({ \ 180 long __gu_err = -EFAULT; \ 181 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 182 unsigned long __gu_val = 0; \ 183 if (access_ok(VERIFY_READ, __gu_ptr, sizeof(*__gu_ptr))) \ 184 __get_user_common(__gu_val, sizeof(*__gu_ptr), \ 185 __gu_ptr, __gu_err); \ 186 (x) = (__force __typeof__(x))__gu_val; \ 187 __gu_err; \ 188 }) 189 190 #define __put_user_asm(val, insn, ptr, err) \ 191 { \ 192 __asm__ __volatile__( \ 193 " movi %0, %3\n" \ 194 "1: " insn " %1, 0(%2)\n" \ 195 " movi %0, 0\n" \ 196 "2:\n" \ 197 " .section __ex_table,\"a\"\n" \ 198 " .word 1b, 2b\n" \ 199 " .previous\n" \ 200 : "=&r" (err) \ 201 : "r" (val), "r" (ptr), "i" (-EFAULT)); \ 202 } 203 204 #define put_user(x, ptr) \ 205 ({ \ 206 long __pu_err = -EFAULT; \ 207 __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ 208 __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x); \ 209 if (access_ok(VERIFY_WRITE, __pu_ptr, sizeof(*__pu_ptr))) { \ 210 switch (sizeof(*__pu_ptr)) { \ 211 case 1: \ 212 __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ 213 break; \ 214 case 2: \ 215 __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ 216 break; \ 217 case 4: \ 218 __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ 219 break; \ 220 default: \ 221 /* XXX: This looks wrong... */ \ 222 __pu_err = 0; \ 223 if (copy_to_user(__pu_ptr, &(__pu_val), \ 224 sizeof(*__pu_ptr))) \ 225 __pu_err = -EFAULT; \ 226 break; \ 227 } \ 228 } \ 229 __pu_err; \ 230 }) 231 232 #define __put_user(x, ptr) put_user(x, ptr) 233 234 #endif /* _ASM_NIOS2_UACCESS_H */ 235