ev67-strlen_user.S 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * arch/alpha/lib/ev67-strlen_user.S
  3. * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
  4. *
  5. * Return the length of the string including the NULL terminator
  6. * (strlen+1) or zero if an error occurred.
  7. *
  8. * In places where it is critical to limit the processing time,
  9. * and the data is not trusted, strnlen_user() should be used.
  10. * It will return a value greater than its second argument if
  11. * that limit would be exceeded. This implementation is allowed
  12. * to access memory beyond the limit, but will not cross a page
  13. * boundary when doing so.
  14. *
  15. * Much of the information about 21264 scheduling/coding comes from:
  16. * Compiler Writer's Guide for the Alpha 21264
  17. * abbreviated as 'CWG' in other comments here
  18. * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
  19. * Scheduling notation:
  20. * E - either cluster
  21. * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
  22. * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
  23. * Try not to change the actual algorithm if possible for consistency.
  24. */
  25. #include <asm/regdef.h>
  26. /* Allow an exception for an insn; exit if we get one. */
  27. #define EX(x,y...) \
  28. 99: x,##y; \
  29. .section __ex_table,"a"; \
  30. .long 99b - .; \
  31. lda v0, $exception-99b(zero); \
  32. .previous
  33. .set noreorder
  34. .set noat
  35. .text
  36. .globl __strlen_user
  37. .ent __strlen_user
  38. .frame sp, 0, ra
  39. .align 4
  40. __strlen_user:
  41. ldah a1, 32767(zero) # do not use plain strlen_user() for strings
  42. # that might be almost 2 GB long; you should
  43. # be using strnlen_user() instead
  44. nop
  45. nop
  46. nop
  47. .globl __strnlen_user
  48. .align 4
  49. __strnlen_user:
  50. .prologue 0
  51. EX( ldq_u t0, 0(a0) ) # L : load first quadword (a0 may be misaligned)
  52. lda t1, -1(zero) # E :
  53. insqh t1, a0, t1 # U :
  54. andnot a0, 7, v0 # E :
  55. or t1, t0, t0 # E :
  56. subq a0, 1, a0 # E : get our +1 for the return
  57. cmpbge zero, t0, t1 # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0
  58. subq a1, 7, t2 # E :
  59. subq a0, v0, t0 # E :
  60. bne t1, $found # U :
  61. addq t2, t0, t2 # E :
  62. addq a1, 1, a1 # E :
  63. nop # E :
  64. nop # E :
  65. .align 4
  66. $loop: ble t2, $limit # U :
  67. EX( ldq t0, 8(v0) ) # L :
  68. nop # E :
  69. nop # E :
  70. cmpbge zero, t0, t1 # E :
  71. subq t2, 8, t2 # E :
  72. addq v0, 8, v0 # E : addr += 8
  73. beq t1, $loop # U :
  74. $found: cttz t1, t2 # U0 :
  75. addq v0, t2, v0 # E :
  76. subq v0, a0, v0 # E :
  77. ret # L0 :
  78. $exception:
  79. nop
  80. nop
  81. nop
  82. ret
  83. .align 4 # currently redundant
  84. $limit:
  85. nop
  86. nop
  87. subq a1, t2, v0
  88. ret
  89. .end __strlen_user