usercopy.c 8.5 KB

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