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 if (!access_ok(VERIFY_READ, from, n)) 106 return n; 107 return __copy_from_user(to, from, n); 108 } 109 110 static inline long copy_to_user(void __user *to, const void *from, 111 unsigned long n) 112 { 113 if (!access_ok(VERIFY_WRITE, to, n)) 114 return n; 115 return __copy_to_user(to, from, n); 116 } 117 118 extern long strncpy_from_user(char *__to, const char __user *__from, 119 long __len); 120 extern long strnlen_user(const char __user *s, long n); 121 122 #define __copy_from_user_inatomic __copy_from_user 123 #define __copy_to_user_inatomic __copy_to_user 124 125 /* Optimized macros */ 126 #define __get_user_asm(val, insn, addr, err) \ 127 { \ 128 __asm__ __volatile__( \ 129 " movi %0, %3\n" \ 130 "1: " insn " %1, 0(%2)\n" \ 131 " movi %0, 0\n" \ 132 "2:\n" \ 133 " .section __ex_table,\"a\"\n" \ 134 " .word 1b, 2b\n" \ 135 " .previous" \ 136 : "=&r" (err), "=r" (val) \ 137 : "r" (addr), "i" (-EFAULT)); \ 138 } 139 140 #define __get_user_unknown(val, size, ptr, err) do { \ 141 err = 0; \ 142 if (copy_from_user(&(val), ptr, size)) { \ 143 err = -EFAULT; \ 144 } \ 145 } while (0) 146 147 #define __get_user_common(val, size, ptr, err) \ 148 do { \ 149 switch (size) { \ 150 case 1: \ 151 __get_user_asm(val, "ldbu", ptr, err); \ 152 break; \ 153 case 2: \ 154 __get_user_asm(val, "ldhu", ptr, err); \ 155 break; \ 156 case 4: \ 157 __get_user_asm(val, "ldw", ptr, err); \ 158 break; \ 159 default: \ 160 __get_user_unknown(val, size, ptr, err); \ 161 break; \ 162 } \ 163 } while (0) 164 165 #define __get_user(x, ptr) \ 166 ({ \ 167 long __gu_err = -EFAULT; \ 168 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 169 unsigned long __gu_val; \ 170 __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\ 171 (x) = (__force __typeof__(x))__gu_val; \ 172 __gu_err; \ 173 }) 174 175 #define get_user(x, ptr) \ 176 ({ \ 177 long __gu_err = -EFAULT; \ 178 const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ 179 unsigned long __gu_val = 0; \ 180 if (access_ok(VERIFY_READ, __gu_ptr, sizeof(*__gu_ptr))) \ 181 __get_user_common(__gu_val, sizeof(*__gu_ptr), \ 182 __gu_ptr, __gu_err); \ 183 (x) = (__force __typeof__(x))__gu_val; \ 184 __gu_err; \ 185 }) 186 187 #define __put_user_asm(val, insn, ptr, err) \ 188 { \ 189 __asm__ __volatile__( \ 190 " movi %0, %3\n" \ 191 "1: " insn " %1, 0(%2)\n" \ 192 " movi %0, 0\n" \ 193 "2:\n" \ 194 " .section __ex_table,\"a\"\n" \ 195 " .word 1b, 2b\n" \ 196 " .previous\n" \ 197 : "=&r" (err) \ 198 : "r" (val), "r" (ptr), "i" (-EFAULT)); \ 199 } 200 201 #define put_user(x, ptr) \ 202 ({ \ 203 long __pu_err = -EFAULT; \ 204 __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ 205 __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x); \ 206 if (access_ok(VERIFY_WRITE, __pu_ptr, sizeof(*__pu_ptr))) { \ 207 switch (sizeof(*__pu_ptr)) { \ 208 case 1: \ 209 __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ 210 break; \ 211 case 2: \ 212 __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ 213 break; \ 214 case 4: \ 215 __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ 216 break; \ 217 default: \ 218 /* XXX: This looks wrong... */ \ 219 __pu_err = 0; \ 220 if (copy_to_user(__pu_ptr, &(__pu_val), \ 221 sizeof(*__pu_ptr))) \ 222 __pu_err = -EFAULT; \ 223 break; \ 224 } \ 225 } \ 226 __pu_err; \ 227 }) 228 229 #define __put_user(x, ptr) put_user(x, ptr) 230 231 #endif /* _ASM_NIOS2_UACCESS_H */ 232