csumpartial.S 2.9 KB

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