usercopy.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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 = -EFAULT;
  88. if (access_ok(VERIFY_READ, src, 1))
  89. __do_strncpy_from_user(dst, src, count, res);
  90. return res;
  91. }
  92. /*
  93. * Zero Userspace
  94. */
  95. #ifdef CONFIG_ISA_DUAL_ISSUE
  96. #define __do_clear_user(addr,size) \
  97. do { \
  98. int __dst, __c; \
  99. __asm__ __volatile__( \
  100. " beqz %1, 9f\n" \
  101. " and3 r14, %0, #3\n" \
  102. " bnez r14, 2f\n" \
  103. " and3 r14, %1, #3\n" \
  104. " bnez r14, 2f\n" \
  105. " and3 %1, %1, #3\n" \
  106. " beqz %2, 2f\n" \
  107. " addi %0, #-4\n" \
  108. " .fillinsn\n" \
  109. "0: ; word clear \n" \
  110. " st %6, @+%0 || addi %2, #-1\n" \
  111. " bnez %2, 0b\n" \
  112. " beqz %1, 9f\n" \
  113. " .fillinsn\n" \
  114. "2: ; byte clear \n" \
  115. " stb %6, @%0 || addi %1, #-1\n" \
  116. " addi %0, #1\n" \
  117. " bnez %1, 2b\n" \
  118. " .fillinsn\n" \
  119. "9:\n" \
  120. ".section .fixup,\"ax\"\n" \
  121. " .balign 4\n" \
  122. "4: slli %2, #2\n" \
  123. " seth r14, #high(9b)\n" \
  124. " or3 r14, r14, #low(9b)\n" \
  125. " jmp r14 || add %1, %2\n" \
  126. ".previous\n" \
  127. ".section __ex_table,\"a\"\n" \
  128. " .balign 4\n" \
  129. " .long 0b,4b\n" \
  130. " .long 2b,9b\n" \
  131. ".previous\n" \
  132. : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
  133. : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
  134. : "r14", "cbit", "memory"); \
  135. } while (0)
  136. #else /* not CONFIG_ISA_DUAL_ISSUE */
  137. #define __do_clear_user(addr,size) \
  138. do { \
  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: st %6, @+%0 ; word clear \n" \
  151. " addi %2, #-1\n" \
  152. " bnez %2, 0b\n" \
  153. " beqz %1, 9f\n" \
  154. " .fillinsn\n" \
  155. "2: stb %6, @%0 ; byte clear \n" \
  156. " 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. " add %1, %2\n" \
  165. " seth r14, #high(9b)\n" \
  166. " or3 r14, r14, #low(9b)\n" \
  167. " jmp r14\n" \
  168. ".previous\n" \
  169. ".section __ex_table,\"a\"\n" \
  170. " .balign 4\n" \
  171. " .long 0b,4b\n" \
  172. " .long 2b,9b\n" \
  173. ".previous\n" \
  174. : "=&r"(__dst), "=&r"(size), "=&r"(__c) \
  175. : "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
  176. : "r14", "cbit", "memory"); \
  177. } while (0)
  178. #endif /* not CONFIG_ISA_DUAL_ISSUE */
  179. unsigned long
  180. clear_user(void __user *to, unsigned long n)
  181. {
  182. if (access_ok(VERIFY_WRITE, to, n))
  183. __do_clear_user(to, n);
  184. return n;
  185. }
  186. unsigned long
  187. __clear_user(void __user *to, unsigned long n)
  188. {
  189. __do_clear_user(to, n);
  190. return n;
  191. }
  192. /*
  193. * Return the size of a string (including the ending 0)
  194. *
  195. * Return 0 on exception, a value greater than N if too long
  196. */
  197. #ifdef CONFIG_ISA_DUAL_ISSUE
  198. long strnlen_user(const char __user *s, long n)
  199. {
  200. unsigned long mask = -__addr_ok(s);
  201. unsigned long res;
  202. __asm__ __volatile__(
  203. " and %0, %5 || mv r1, %1\n"
  204. " beqz %0, strnlen_exit\n"
  205. " and3 r0, %1, #3\n"
  206. " bnez r0, strnlen_byte_loop\n"
  207. " cmpui %0, #4\n"
  208. " bc strnlen_byte_loop\n"
  209. "strnlen_word_loop:\n"
  210. "0: ld r0, @%1+\n"
  211. " pcmpbz r0\n"
  212. " bc strnlen_last_bytes_fixup\n"
  213. " addi %0, #-4\n"
  214. " beqz %0, strnlen_exit\n"
  215. " bgtz %0, strnlen_word_loop\n"
  216. "strnlen_last_bytes:\n"
  217. " mv %0, %4\n"
  218. "strnlen_last_bytes_fixup:\n"
  219. " addi %1, #-4\n"
  220. "strnlen_byte_loop:\n"
  221. "1: ldb r0, @%1 || addi %0, #-1\n"
  222. " beqz r0, strnlen_exit\n"
  223. " addi %1, #1\n"
  224. " bnez %0, strnlen_byte_loop\n"
  225. "strnlen_exit:\n"
  226. " sub %1, r1\n"
  227. " add3 %0, %1, #1\n"
  228. " .fillinsn\n"
  229. "9:\n"
  230. ".section .fixup,\"ax\"\n"
  231. " .balign 4\n"
  232. "4: addi %1, #-4\n"
  233. " .fillinsn\n"
  234. "5: seth r1, #high(9b)\n"
  235. " or3 r1, r1, #low(9b)\n"
  236. " jmp r1 || ldi %0, #0\n"
  237. ".previous\n"
  238. ".section __ex_table,\"a\"\n"
  239. " .balign 4\n"
  240. " .long 0b,4b\n"
  241. " .long 1b,5b\n"
  242. ".previous"
  243. : "=&r" (res), "=r" (s)
  244. : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
  245. : "r0", "r1", "cbit");
  246. /* NOTE: strnlen_user() algorithm:
  247. * {
  248. * char *p;
  249. * for (p = s; n-- && *p != '\0'; ++p)
  250. * ;
  251. * return p - s + 1;
  252. * }
  253. */
  254. /* NOTE: If a null char. exists, return 0.
  255. * if ((x - 0x01010101) & ~x & 0x80808080)\n"
  256. * return 0;\n"
  257. */
  258. return res & mask;
  259. }
  260. #else /* not CONFIG_ISA_DUAL_ISSUE */
  261. long strnlen_user(const char __user *s, long n)
  262. {
  263. unsigned long mask = -__addr_ok(s);
  264. unsigned long res;
  265. __asm__ __volatile__(
  266. " and %0, %5\n"
  267. " mv r1, %1\n"
  268. " beqz %0, strnlen_exit\n"
  269. " and3 r0, %1, #3\n"
  270. " bnez r0, strnlen_byte_loop\n"
  271. " cmpui %0, #4\n"
  272. " bc strnlen_byte_loop\n"
  273. " sll3 r3, %6, #7\n"
  274. "strnlen_word_loop:\n"
  275. "0: ld r0, @%1+\n"
  276. " not r2, r0\n"
  277. " sub r0, %6\n"
  278. " and r2, r3\n"
  279. " and r2, r0\n"
  280. " bnez r2, strnlen_last_bytes_fixup\n"
  281. " addi %0, #-4\n"
  282. " beqz %0, strnlen_exit\n"
  283. " bgtz %0, strnlen_word_loop\n"
  284. "strnlen_last_bytes:\n"
  285. " mv %0, %4\n"
  286. "strnlen_last_bytes_fixup:\n"
  287. " addi %1, #-4\n"
  288. "strnlen_byte_loop:\n"
  289. "1: ldb r0, @%1\n"
  290. " addi %0, #-1\n"
  291. " beqz r0, strnlen_exit\n"
  292. " addi %1, #1\n"
  293. " bnez %0, strnlen_byte_loop\n"
  294. "strnlen_exit:\n"
  295. " sub %1, r1\n"
  296. " add3 %0, %1, #1\n"
  297. " .fillinsn\n"
  298. "9:\n"
  299. ".section .fixup,\"ax\"\n"
  300. " .balign 4\n"
  301. "4: addi %1, #-4\n"
  302. " .fillinsn\n"
  303. "5: ldi %0, #0\n"
  304. " seth r1, #high(9b)\n"
  305. " or3 r1, r1, #low(9b)\n"
  306. " jmp r1\n"
  307. ".previous\n"
  308. ".section __ex_table,\"a\"\n"
  309. " .balign 4\n"
  310. " .long 0b,4b\n"
  311. " .long 1b,5b\n"
  312. ".previous"
  313. : "=&r" (res), "=r" (s)
  314. : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
  315. : "r0", "r1", "r2", "r3", "cbit");
  316. /* NOTE: strnlen_user() algorithm:
  317. * {
  318. * char *p;
  319. * for (p = s; n-- && *p != '\0'; ++p)
  320. * ;
  321. * return p - s + 1;
  322. * }
  323. */
  324. /* NOTE: If a null char. exists, return 0.
  325. * if ((x - 0x01010101) & ~x & 0x80808080)\n"
  326. * return 0;\n"
  327. */
  328. return res & mask;
  329. }
  330. #endif /* CONFIG_ISA_DUAL_ISSUE */