usercopy_32.S 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Copyright 2010 Tilera Corporation. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation, version 2.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11. * NON INFRINGEMENT. See the GNU General Public License for
  12. * more details.
  13. */
  14. #include <linux/linkage.h>
  15. #include <asm/errno.h>
  16. #include <asm/cache.h>
  17. #include <arch/chip.h>
  18. /* Access user memory, but use MMU to avoid propagating kernel exceptions. */
  19. .pushsection .fixup,"ax"
  20. get_user_fault:
  21. { move r0, zero; move r1, zero }
  22. { movei r2, -EFAULT; jrp lr }
  23. ENDPROC(get_user_fault)
  24. put_user_fault:
  25. { movei r0, -EFAULT; jrp lr }
  26. ENDPROC(put_user_fault)
  27. .popsection
  28. /*
  29. * __get_user_N functions take a pointer in r0, and return 0 in r2
  30. * on success, with the value in r0; or else -EFAULT in r2.
  31. */
  32. #define __get_user_N(bytes, LOAD) \
  33. STD_ENTRY(__get_user_##bytes); \
  34. 1: { LOAD r0, r0; move r1, zero; move r2, zero }; \
  35. jrp lr; \
  36. STD_ENDPROC(__get_user_##bytes); \
  37. .pushsection __ex_table,"a"; \
  38. .word 1b, get_user_fault; \
  39. .popsection
  40. __get_user_N(1, lb_u)
  41. __get_user_N(2, lh_u)
  42. __get_user_N(4, lw)
  43. /*
  44. * __get_user_8 takes a pointer in r0, and returns 0 in r2
  45. * on success, with the value in r0/r1; or else -EFAULT in r2.
  46. */
  47. STD_ENTRY(__get_user_8);
  48. 1: { lw r0, r0; addi r1, r0, 4 };
  49. 2: { lw r1, r1; move r2, zero };
  50. jrp lr;
  51. STD_ENDPROC(__get_user_8);
  52. .pushsection __ex_table,"a";
  53. .word 1b, get_user_fault;
  54. .word 2b, get_user_fault;
  55. .popsection
  56. /*
  57. * __put_user_N functions take a value in r0 and a pointer in r1,
  58. * and return 0 in r0 on success or -EFAULT on failure.
  59. */
  60. #define __put_user_N(bytes, STORE) \
  61. STD_ENTRY(__put_user_##bytes); \
  62. 1: { STORE r1, r0; move r0, zero }; \
  63. jrp lr; \
  64. STD_ENDPROC(__put_user_##bytes); \
  65. .pushsection __ex_table,"a"; \
  66. .word 1b, put_user_fault; \
  67. .popsection
  68. __put_user_N(1, sb)
  69. __put_user_N(2, sh)
  70. __put_user_N(4, sw)
  71. /*
  72. * __put_user_8 takes a value in r0/r1 and a pointer in r2,
  73. * and returns 0 in r0 on success or -EFAULT on failure.
  74. */
  75. STD_ENTRY(__put_user_8)
  76. 1: { sw r2, r0; addi r2, r2, 4 }
  77. 2: { sw r2, r1; move r0, zero }
  78. jrp lr
  79. STD_ENDPROC(__put_user_8)
  80. .pushsection __ex_table,"a"
  81. .word 1b, put_user_fault
  82. .word 2b, put_user_fault
  83. .popsection
  84. /*
  85. * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
  86. * It returns the length, including the terminating NUL, or zero on exception.
  87. * If length is greater than the bound, returns one plus the bound.
  88. */
  89. STD_ENTRY(strnlen_user_asm)
  90. { bz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */
  91. 1: { lb_u r4, r0; addi r1, r1, -1 }
  92. bz r4, 2f
  93. { bnzt r1, 1b; addi r0, r0, 1 }
  94. 2: { sub r0, r0, r3; jrp lr }
  95. STD_ENDPROC(strnlen_user_asm)
  96. .pushsection .fixup,"ax"
  97. strnlen_user_fault:
  98. { move r0, zero; jrp lr }
  99. ENDPROC(strnlen_user_fault)
  100. .section __ex_table,"a"
  101. .word 1b, strnlen_user_fault
  102. .popsection
  103. /*
  104. * strncpy_from_user_asm takes the kernel target pointer in r0,
  105. * the userspace source pointer in r1, and the length bound (including
  106. * the trailing NUL) in r2. On success, it returns the string length
  107. * (not including the trailing NUL), or -EFAULT on failure.
  108. */
  109. STD_ENTRY(strncpy_from_user_asm)
  110. { bz r2, 2f; move r3, r0 }
  111. 1: { lb_u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
  112. { sb r0, r4; addi r0, r0, 1 }
  113. bz r2, 2f
  114. bnzt r4, 1b
  115. addi r0, r0, -1 /* don't count the trailing NUL */
  116. 2: { sub r0, r0, r3; jrp lr }
  117. STD_ENDPROC(strncpy_from_user_asm)
  118. .pushsection .fixup,"ax"
  119. strncpy_from_user_fault:
  120. { movei r0, -EFAULT; jrp lr }
  121. ENDPROC(strncpy_from_user_fault)
  122. .section __ex_table,"a"
  123. .word 1b, strncpy_from_user_fault
  124. .popsection
  125. /*
  126. * clear_user_asm takes the user target address in r0 and the
  127. * number of bytes to zero in r1.
  128. * It returns the number of uncopiable bytes (hopefully zero) in r0.
  129. * Note that we don't use a separate .fixup section here since we fall
  130. * through into the "fixup" code as the last straight-line bundle anyway.
  131. */
  132. STD_ENTRY(clear_user_asm)
  133. { bz r1, 2f; or r2, r0, r1 }
  134. andi r2, r2, 3
  135. bzt r2, .Lclear_aligned_user_asm
  136. 1: { sb r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
  137. bnzt r1, 1b
  138. 2: { move r0, r1; jrp lr }
  139. .pushsection __ex_table,"a"
  140. .word 1b, 2b
  141. .popsection
  142. .Lclear_aligned_user_asm:
  143. 1: { sw r0, zero; addi r0, r0, 4; addi r1, r1, -4 }
  144. bnzt r1, 1b
  145. 2: { move r0, r1; jrp lr }
  146. STD_ENDPROC(clear_user_asm)
  147. .pushsection __ex_table,"a"
  148. .word 1b, 2b
  149. .popsection
  150. /*
  151. * flush_user_asm takes the user target address in r0 and the
  152. * number of bytes to flush in r1.
  153. * It returns the number of unflushable bytes (hopefully zero) in r0.
  154. */
  155. STD_ENTRY(flush_user_asm)
  156. bz r1, 2f
  157. { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
  158. { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
  159. { and r0, r0, r2; and r1, r1, r2 }
  160. { sub r1, r1, r0 }
  161. 1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
  162. { addi r0, r0, CHIP_FLUSH_STRIDE(); bnzt r1, 1b }
  163. 2: { move r0, r1; jrp lr }
  164. STD_ENDPROC(flush_user_asm)
  165. .pushsection __ex_table,"a"
  166. .word 1b, 2b
  167. .popsection
  168. /*
  169. * inv_user_asm takes the user target address in r0 and the
  170. * number of bytes to invalidate in r1.
  171. * It returns the number of not inv'able bytes (hopefully zero) in r0.
  172. */
  173. STD_ENTRY(inv_user_asm)
  174. bz r1, 2f
  175. { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
  176. { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
  177. { and r0, r0, r2; and r1, r1, r2 }
  178. { sub r1, r1, r0 }
  179. 1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
  180. { addi r0, r0, CHIP_INV_STRIDE(); bnzt r1, 1b }
  181. 2: { move r0, r1; jrp lr }
  182. STD_ENDPROC(inv_user_asm)
  183. .pushsection __ex_table,"a"
  184. .word 1b, 2b
  185. .popsection
  186. /*
  187. * finv_user_asm takes the user target address in r0 and the
  188. * number of bytes to flush-invalidate in r1.
  189. * It returns the number of not finv'able bytes (hopefully zero) in r0.
  190. */
  191. STD_ENTRY(finv_user_asm)
  192. bz r1, 2f
  193. { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
  194. { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
  195. { and r0, r0, r2; and r1, r1, r2 }
  196. { sub r1, r1, r0 }
  197. 1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
  198. { addi r0, r0, CHIP_FINV_STRIDE(); bnzt r1, 1b }
  199. 2: { move r0, r1; jrp lr }
  200. STD_ENDPROC(finv_user_asm)
  201. .pushsection __ex_table,"a"
  202. .word 1b, 2b
  203. .popsection