csumpartial.S 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * linux/arch/arm/lib/csumpartial.S
  3. *
  4. * Copyright (C) 1995-1998 Russell King
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/linkage.h>
  11. #include <asm/assembler.h>
  12. #include <asm/export.h>
  13. .text
  14. /*
  15. * Function: __u32 csum_partial(const char *src, int len, __u32 sum)
  16. * Params : r0 = buffer, r1 = len, r2 = checksum
  17. * Returns : r0 = new checksum
  18. */
  19. buf .req r0
  20. len .req r1
  21. sum .req r2
  22. td0 .req r3
  23. td1 .req r4 @ save before use
  24. td2 .req r5 @ save before use
  25. td3 .req lr
  26. .Lzero: mov r0, sum
  27. add sp, sp, #4
  28. ldr pc, [sp], #4
  29. /*
  30. * Handle 0 to 7 bytes, with any alignment of source and
  31. * destination pointers. Note that when we get here, C = 0
  32. */
  33. .Lless8: teq len, #0 @ check for zero count
  34. beq .Lzero
  35. /* we must have at least one byte. */
  36. tst buf, #1 @ odd address?
  37. movne sum, sum, ror #8
  38. ldrneb td0, [buf], #1
  39. subne len, len, #1
  40. adcnes sum, sum, td0, put_byte_1
  41. .Lless4: tst len, #6
  42. beq .Lless8_byte
  43. /* we are now half-word aligned */
  44. .Lless8_wordlp:
  45. #if __LINUX_ARM_ARCH__ >= 4
  46. ldrh td0, [buf], #2
  47. sub len, len, #2
  48. #else
  49. ldrb td0, [buf], #1
  50. ldrb td3, [buf], #1
  51. sub len, len, #2
  52. #ifndef __ARMEB__
  53. orr td0, td0, td3, lsl #8
  54. #else
  55. orr td0, td3, td0, lsl #8
  56. #endif
  57. #endif
  58. adcs sum, sum, td0
  59. tst len, #6
  60. bne .Lless8_wordlp
  61. .Lless8_byte: tst len, #1 @ odd number of bytes
  62. ldrneb td0, [buf], #1 @ include last byte
  63. adcnes sum, sum, td0, put_byte_0 @ update checksum
  64. .Ldone: adc r0, sum, #0 @ collect up the last carry
  65. ldr td0, [sp], #4
  66. tst td0, #1 @ check buffer alignment
  67. movne r0, r0, ror #8 @ rotate checksum by 8 bits
  68. ldr pc, [sp], #4 @ return
  69. .Lnot_aligned: tst buf, #1 @ odd address
  70. ldrneb td0, [buf], #1 @ make even
  71. subne len, len, #1
  72. adcnes sum, sum, td0, put_byte_1 @ update checksum
  73. tst buf, #2 @ 32-bit aligned?
  74. #if __LINUX_ARM_ARCH__ >= 4
  75. ldrneh td0, [buf], #2 @ make 32-bit aligned
  76. subne len, len, #2
  77. #else
  78. ldrneb td0, [buf], #1
  79. ldrneb ip, [buf], #1
  80. subne len, len, #2
  81. #ifndef __ARMEB__
  82. orrne td0, td0, ip, lsl #8
  83. #else
  84. orrne td0, ip, td0, lsl #8
  85. #endif
  86. #endif
  87. adcnes sum, sum, td0 @ update checksum
  88. ret lr
  89. ENTRY(csum_partial)
  90. stmfd sp!, {buf, lr}
  91. cmp len, #8 @ Ensure that we have at least
  92. blo .Lless8 @ 8 bytes to copy.
  93. tst buf, #1
  94. movne sum, sum, ror #8
  95. adds sum, sum, #0 @ C = 0
  96. tst buf, #3 @ Test destination alignment
  97. blne .Lnot_aligned @ align destination, return here
  98. 1: bics ip, len, #31
  99. beq 3f
  100. stmfd sp!, {r4 - r5}
  101. 2: ldmia buf!, {td0, td1, td2, td3}
  102. adcs sum, sum, td0
  103. adcs sum, sum, td1
  104. adcs sum, sum, td2
  105. adcs sum, sum, td3
  106. ldmia buf!, {td0, td1, td2, td3}
  107. adcs sum, sum, td0
  108. adcs sum, sum, td1
  109. adcs sum, sum, td2
  110. adcs sum, sum, td3
  111. sub ip, ip, #32
  112. teq ip, #0
  113. bne 2b
  114. ldmfd sp!, {r4 - r5}
  115. 3: tst len, #0x1c @ should not change C
  116. beq .Lless4
  117. 4: ldr td0, [buf], #4
  118. sub len, len, #4
  119. adcs sum, sum, td0
  120. tst len, #0x1c
  121. bne 4b
  122. b .Lless4
  123. ENDPROC(csum_partial)
  124. EXPORT_SYMBOL(csum_partial)