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