copy_in_user.S 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /* copy_in_user.S: Copy from userspace to userspace.
  2. *
  3. * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  4. */
  5. #include <asm/asi.h>
  6. #define XCC xcc
  7. #define EX(x,y) \
  8. 98: x,y; \
  9. .section .fixup; \
  10. .align 4; \
  11. 99: retl; \
  12. mov 1, %o0; \
  13. .section __ex_table,"a";\
  14. .align 4; \
  15. .word 98b, 99b; \
  16. .text; \
  17. .align 4;
  18. .register %g2,#scratch
  19. .register %g3,#scratch
  20. .text
  21. .align 32
  22. /* Don't try to get too fancy here, just nice and
  23. * simple. This is predominantly used for well aligned
  24. * small copies in the compat layer. It is also used
  25. * to copy register windows around during thread cloning.
  26. */
  27. .globl ___copy_in_user
  28. .type ___copy_in_user,#function
  29. ___copy_in_user: /* %o0=dst, %o1=src, %o2=len */
  30. /* Writing to %asi is _expensive_ so we hardcode it.
  31. * Reading %asi to check for KERNEL_DS is comparatively
  32. * cheap.
  33. */
  34. rd %asi, %g1
  35. cmp %g1, ASI_AIUS
  36. bne,pn %icc, memcpy_user_stub
  37. nop
  38. cmp %o2, 0
  39. be,pn %XCC, 85f
  40. or %o0, %o1, %o3
  41. cmp %o2, 16
  42. bleu,a,pn %XCC, 80f
  43. or %o3, %o2, %o3
  44. /* 16 < len <= 64 */
  45. andcc %o3, 0x7, %g0
  46. bne,pn %XCC, 90f
  47. sub %o0, %o1, %o3
  48. andn %o2, 0x7, %o4
  49. and %o2, 0x7, %o2
  50. 1: subcc %o4, 0x8, %o4
  51. EX(ldxa [%o1] %asi, %o5)
  52. EX(stxa %o5, [%o1 + %o3] ASI_AIUS)
  53. bgu,pt %XCC, 1b
  54. add %o1, 0x8, %o1
  55. andcc %o2, 0x4, %g0
  56. be,pt %XCC, 1f
  57. nop
  58. sub %o2, 0x4, %o2
  59. EX(lduwa [%o1] %asi, %o5)
  60. EX(stwa %o5, [%o1 + %o3] ASI_AIUS)
  61. add %o1, 0x4, %o1
  62. 1: cmp %o2, 0
  63. be,pt %XCC, 85f
  64. nop
  65. ba,pt %xcc, 90f
  66. nop
  67. 80: /* 0 < len <= 16 */
  68. andcc %o3, 0x3, %g0
  69. bne,pn %XCC, 90f
  70. sub %o0, %o1, %o3
  71. 82:
  72. subcc %o2, 4, %o2
  73. EX(lduwa [%o1] %asi, %g1)
  74. EX(stwa %g1, [%o1 + %o3] ASI_AIUS)
  75. bgu,pt %XCC, 82b
  76. add %o1, 4, %o1
  77. 85: retl
  78. clr %o0
  79. .align 32
  80. 90:
  81. subcc %o2, 1, %o2
  82. EX(lduba [%o1] %asi, %g1)
  83. EX(stba %g1, [%o1 + %o3] ASI_AIUS)
  84. bgu,pt %XCC, 90b
  85. add %o1, 1, %o1
  86. retl
  87. clr %o0
  88. .size ___copy_in_user, .-___copy_in_user
  89. /* Act like copy_{to,in}_user(), ie. return zero instead
  90. * of original destination pointer. This is invoked when
  91. * copy_{to,in}_user() finds that %asi is kernel space.
  92. */
  93. .globl memcpy_user_stub
  94. .type memcpy_user_stub,#function
  95. memcpy_user_stub:
  96. save %sp, -192, %sp
  97. mov %i0, %o0
  98. mov %i1, %o1
  99. call memcpy
  100. mov %i2, %o2
  101. ret
  102. restore %g0, %g0, %o0
  103. .size memcpy_user_stub, .-memcpy_user_stub