Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.12 391 lines 9.0 kB view raw
1/* 2 * User address space access functions. 3 * The non inlined parts of asm-m32r/uaccess.h are here. 4 * 5 * Copyright 1997 Andi Kleen <ak@muc.de> 6 * Copyright 1997 Linus Torvalds 7 * Copyright 2001, 2002, 2004 Hirokazu Takata 8 */ 9#include <linux/config.h> 10#include <linux/prefetch.h> 11#include <linux/string.h> 12#include <linux/thread_info.h> 13#include <asm/uaccess.h> 14 15unsigned long 16__generic_copy_to_user(void *to, const void *from, unsigned long n) 17{ 18 prefetch(from); 19 if (access_ok(VERIFY_WRITE, to, n)) 20 __copy_user(to,from,n); 21 return n; 22} 23 24unsigned long 25__generic_copy_from_user(void *to, const void *from, unsigned long n) 26{ 27 prefetchw(to); 28 if (access_ok(VERIFY_READ, from, n)) 29 __copy_user_zeroing(to,from,n); 30 else 31 memset(to, 0, n); 32 return n; 33} 34 35 36/* 37 * Copy a null terminated string from userspace. 38 */ 39 40#ifdef CONFIG_ISA_DUAL_ISSUE 41 42#define __do_strncpy_from_user(dst,src,count,res) \ 43do { \ 44 int __d0, __d1, __d2; \ 45 __asm__ __volatile__( \ 46 " beqz %1, 2f\n" \ 47 " .fillinsn\n" \ 48 "0: ldb r14, @%3 || addi %3, #1\n" \ 49 " stb r14, @%4 || addi %4, #1\n" \ 50 " beqz r14, 1f\n" \ 51 " addi %1, #-1\n" \ 52 " bnez %1, 0b\n" \ 53 " .fillinsn\n" \ 54 "1: sub %0, %1\n" \ 55 " .fillinsn\n" \ 56 "2:\n" \ 57 ".section .fixup,\"ax\"\n" \ 58 " .balign 4\n" \ 59 "3: seth r14, #high(2b)\n" \ 60 " or3 r14, r14, #low(2b)\n" \ 61 " jmp r14 || ldi %0, #%5\n" \ 62 ".previous\n" \ 63 ".section __ex_table,\"a\"\n" \ 64 " .balign 4\n" \ 65 " .long 0b,3b\n" \ 66 ".previous" \ 67 : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ 68 "=&r" (__d2) \ 69 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ 70 "4"(dst) \ 71 : "r14", "cbit", "memory"); \ 72} while (0) 73 74#else /* not CONFIG_ISA_DUAL_ISSUE */ 75 76#define __do_strncpy_from_user(dst,src,count,res) \ 77do { \ 78 int __d0, __d1, __d2; \ 79 __asm__ __volatile__( \ 80 " beqz %1, 2f\n" \ 81 " .fillinsn\n" \ 82 "0: ldb r14, @%3\n" \ 83 " stb r14, @%4\n" \ 84 " addi %3, #1\n" \ 85 " addi %4, #1\n" \ 86 " beqz r14, 1f\n" \ 87 " addi %1, #-1\n" \ 88 " bnez %1, 0b\n" \ 89 " .fillinsn\n" \ 90 "1: sub %0, %1\n" \ 91 " .fillinsn\n" \ 92 "2:\n" \ 93 ".section .fixup,\"ax\"\n" \ 94 " .balign 4\n" \ 95 "3: ldi %0, #%5\n" \ 96 " seth r14, #high(2b)\n" \ 97 " or3 r14, r14, #low(2b)\n" \ 98 " jmp r14\n" \ 99 ".previous\n" \ 100 ".section __ex_table,\"a\"\n" \ 101 " .balign 4\n" \ 102 " .long 0b,3b\n" \ 103 ".previous" \ 104 : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ 105 "=&r" (__d2) \ 106 : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ 107 "4"(dst) \ 108 : "r14", "cbit", "memory"); \ 109} while (0) 110 111#endif /* CONFIG_ISA_DUAL_ISSUE */ 112 113long 114__strncpy_from_user(char *dst, const char *src, long count) 115{ 116 long res; 117 __do_strncpy_from_user(dst, src, count, res); 118 return res; 119} 120 121long 122strncpy_from_user(char *dst, const char *src, long count) 123{ 124 long res = -EFAULT; 125 if (access_ok(VERIFY_READ, src, 1)) 126 __do_strncpy_from_user(dst, src, count, res); 127 return res; 128} 129 130 131/* 132 * Zero Userspace 133 */ 134 135#ifdef CONFIG_ISA_DUAL_ISSUE 136 137#define __do_clear_user(addr,size) \ 138do { \ 139 int __dst, __c; \ 140 __asm__ __volatile__( \ 141 " beqz %1, 9f\n" \ 142 " and3 r14, %0, #3\n" \ 143 " bnez r14, 2f\n" \ 144 " and3 r14, %1, #3\n" \ 145 " bnez r14, 2f\n" \ 146 " and3 %1, %1, #3\n" \ 147 " beqz %2, 2f\n" \ 148 " addi %0, #-4\n" \ 149 " .fillinsn\n" \ 150 "0: ; word clear \n" \ 151 " st %6, @+%0 || addi %2, #-1\n" \ 152 " bnez %2, 0b\n" \ 153 " beqz %1, 9f\n" \ 154 " .fillinsn\n" \ 155 "2: ; byte clear \n" \ 156 " stb %6, @%0 || addi %1, #-1\n" \ 157 " addi %0, #1\n" \ 158 " bnez %1, 2b\n" \ 159 " .fillinsn\n" \ 160 "9:\n" \ 161 ".section .fixup,\"ax\"\n" \ 162 " .balign 4\n" \ 163 "4: slli %2, #2\n" \ 164 " seth r14, #high(9b)\n" \ 165 " or3 r14, r14, #low(9b)\n" \ 166 " jmp r14 || add %1, %2\n" \ 167 ".previous\n" \ 168 ".section __ex_table,\"a\"\n" \ 169 " .balign 4\n" \ 170 " .long 0b,4b\n" \ 171 " .long 2b,9b\n" \ 172 ".previous\n" \ 173 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ 174 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ 175 : "r14", "cbit", "memory"); \ 176} while (0) 177 178#else /* not CONFIG_ISA_DUAL_ISSUE */ 179 180#define __do_clear_user(addr,size) \ 181do { \ 182 int __dst, __c; \ 183 __asm__ __volatile__( \ 184 " beqz %1, 9f\n" \ 185 " and3 r14, %0, #3\n" \ 186 " bnez r14, 2f\n" \ 187 " and3 r14, %1, #3\n" \ 188 " bnez r14, 2f\n" \ 189 " and3 %1, %1, #3\n" \ 190 " beqz %2, 2f\n" \ 191 " addi %0, #-4\n" \ 192 " .fillinsn\n" \ 193 "0: st %6, @+%0 ; word clear \n" \ 194 " addi %2, #-1\n" \ 195 " bnez %2, 0b\n" \ 196 " beqz %1, 9f\n" \ 197 " .fillinsn\n" \ 198 "2: stb %6, @%0 ; byte clear \n" \ 199 " addi %1, #-1\n" \ 200 " addi %0, #1\n" \ 201 " bnez %1, 2b\n" \ 202 " .fillinsn\n" \ 203 "9:\n" \ 204 ".section .fixup,\"ax\"\n" \ 205 " .balign 4\n" \ 206 "4: slli %2, #2\n" \ 207 " add %1, %2\n" \ 208 " seth r14, #high(9b)\n" \ 209 " or3 r14, r14, #low(9b)\n" \ 210 " jmp r14\n" \ 211 ".previous\n" \ 212 ".section __ex_table,\"a\"\n" \ 213 " .balign 4\n" \ 214 " .long 0b,4b\n" \ 215 " .long 2b,9b\n" \ 216 ".previous\n" \ 217 : "=&r"(__dst), "=&r"(size), "=&r"(__c) \ 218 : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \ 219 : "r14", "cbit", "memory"); \ 220} while (0) 221 222#endif /* not CONFIG_ISA_DUAL_ISSUE */ 223 224unsigned long 225clear_user(void *to, unsigned long n) 226{ 227 if (access_ok(VERIFY_WRITE, to, n)) 228 __do_clear_user(to, n); 229 return n; 230} 231 232unsigned long 233__clear_user(void *to, unsigned long n) 234{ 235 __do_clear_user(to, n); 236 return n; 237} 238 239/* 240 * Return the size of a string (including the ending 0) 241 * 242 * Return 0 on exception, a value greater than N if too long 243 */ 244 245#ifdef CONFIG_ISA_DUAL_ISSUE 246 247long strnlen_user(const char *s, long n) 248{ 249 unsigned long mask = -__addr_ok(s); 250 unsigned long res; 251 252 __asm__ __volatile__( 253 " and %0, %5 || mv r1, %1\n" 254 " beqz %0, strnlen_exit\n" 255 " and3 r0, %1, #3\n" 256 " bnez r0, strnlen_byte_loop\n" 257 " cmpui %0, #4\n" 258 " bc strnlen_byte_loop\n" 259 "strnlen_word_loop:\n" 260 "0: ld r0, @%1+\n" 261 " pcmpbz r0\n" 262 " bc strnlen_last_bytes_fixup\n" 263 " addi %0, #-4\n" 264 " beqz %0, strnlen_exit\n" 265 " bgtz %0, strnlen_word_loop\n" 266 "strnlen_last_bytes:\n" 267 " mv %0, %4\n" 268 "strnlen_last_bytes_fixup:\n" 269 " addi %1, #-4\n" 270 "strnlen_byte_loop:\n" 271 "1: ldb r0, @%1 || addi %0, #-1\n" 272 " beqz r0, strnlen_exit\n" 273 " addi %1, #1\n" 274 " bnez %0, strnlen_byte_loop\n" 275 "strnlen_exit:\n" 276 " sub %1, r1\n" 277 " add3 %0, %1, #1\n" 278 " .fillinsn\n" 279 "9:\n" 280 ".section .fixup,\"ax\"\n" 281 " .balign 4\n" 282 "4: addi %1, #-4\n" 283 " .fillinsn\n" 284 "5: seth r1, #high(9b)\n" 285 " or3 r1, r1, #low(9b)\n" 286 " jmp r1 || ldi %0, #0\n" 287 ".previous\n" 288 ".section __ex_table,\"a\"\n" 289 " .balign 4\n" 290 " .long 0b,4b\n" 291 " .long 1b,5b\n" 292 ".previous" 293 : "=&r" (res), "=r" (s) 294 : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) 295 : "r0", "r1", "cbit"); 296 297 /* NOTE: strnlen_user() algorism: 298 * { 299 * char *p; 300 * for (p = s; n-- && *p != '\0'; ++p) 301 * ; 302 * return p - s + 1; 303 * } 304 */ 305 306 /* NOTE: If a null char. exists, return 0. 307 * if ((x - 0x01010101) & ~x & 0x80808080)\n" 308 * return 0;\n" 309 */ 310 311 return res & mask; 312} 313 314#else /* not CONFIG_ISA_DUAL_ISSUE */ 315 316long strnlen_user(const char *s, long n) 317{ 318 unsigned long mask = -__addr_ok(s); 319 unsigned long res; 320 321 __asm__ __volatile__( 322 " and %0, %5\n" 323 " mv r1, %1\n" 324 " beqz %0, strnlen_exit\n" 325 " and3 r0, %1, #3\n" 326 " bnez r0, strnlen_byte_loop\n" 327 " cmpui %0, #4\n" 328 " bc strnlen_byte_loop\n" 329 " sll3 r3, %6, #7\n" 330 "strnlen_word_loop:\n" 331 "0: ld r0, @%1+\n" 332 " not r2, r0\n" 333 " sub r0, %6\n" 334 " and r2, r3\n" 335 " and r2, r0\n" 336 " bnez r2, strnlen_last_bytes_fixup\n" 337 " addi %0, #-4\n" 338 " beqz %0, strnlen_exit\n" 339 " bgtz %0, strnlen_word_loop\n" 340 "strnlen_last_bytes:\n" 341 " mv %0, %4\n" 342 "strnlen_last_bytes_fixup:\n" 343 " addi %1, #-4\n" 344 "strnlen_byte_loop:\n" 345 "1: ldb r0, @%1\n" 346 " addi %0, #-1\n" 347 " beqz r0, strnlen_exit\n" 348 " addi %1, #1\n" 349 " bnez %0, strnlen_byte_loop\n" 350 "strnlen_exit:\n" 351 " sub %1, r1\n" 352 " add3 %0, %1, #1\n" 353 " .fillinsn\n" 354 "9:\n" 355 ".section .fixup,\"ax\"\n" 356 " .balign 4\n" 357 "4: addi %1, #-4\n" 358 " .fillinsn\n" 359 "5: ldi %0, #0\n" 360 " seth r1, #high(9b)\n" 361 " or3 r1, r1, #low(9b)\n" 362 " jmp r1\n" 363 ".previous\n" 364 ".section __ex_table,\"a\"\n" 365 " .balign 4\n" 366 " .long 0b,4b\n" 367 " .long 1b,5b\n" 368 ".previous" 369 : "=&r" (res), "=r" (s) 370 : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101) 371 : "r0", "r1", "r2", "r3", "cbit"); 372 373 /* NOTE: strnlen_user() algorism: 374 * { 375 * char *p; 376 * for (p = s; n-- && *p != '\0'; ++p) 377 * ; 378 * return p - s + 1; 379 * } 380 */ 381 382 /* NOTE: If a null char. exists, return 0. 383 * if ((x - 0x01010101) & ~x & 0x80808080)\n" 384 * return 0;\n" 385 */ 386 387 return res & mask; 388} 389 390#endif /* CONFIG_ISA_DUAL_ISSUE */ 391