csumpartial.S 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. .text
  13. /*
  14. * Function: __u32 csum_partial(const char *src, int len, __u32 sum)
  15. * Params : r0 = buffer, r1 = len, r2 = checksum
  16. * Returns : r0 = new checksum
  17. */
  18. buf .req r0
  19. len .req r1
  20. sum .req r2
  21. td0 .req r3
  22. td1 .req r4 @ save before use
  23. td2 .req r5 @ save before use
  24. td3 .req lr
  25. .zero: mov r0, sum
  26. add sp, sp, #4
  27. ldr pc, [sp], #4
  28. /*
  29. * Handle 0 to 7 bytes, with any alignment of source and
  30. * destination pointers. Note that when we get here, C = 0
  31. */
  32. .less8: teq len, #0 @ check for zero count
  33. beq .zero
  34. /* we must have at least one byte. */
  35. tst buf, #1 @ odd address?
  36. ldrneb td0, [buf], #1
  37. subne len, len, #1
  38. adcnes sum, sum, td0, put_byte_1
  39. .less4: tst len, #6
  40. beq .less8_byte
  41. /* we are now half-word aligned */
  42. .less8_wordlp:
  43. #if __LINUX_ARM_ARCH__ >= 4
  44. ldrh td0, [buf], #2
  45. sub len, len, #2
  46. #else
  47. ldrb td0, [buf], #1
  48. ldrb td3, [buf], #1
  49. sub len, len, #2
  50. #ifndef __ARMEB__
  51. orr td0, td0, td3, lsl #8
  52. #else
  53. orr td0, td3, td0, lsl #8
  54. #endif
  55. #endif
  56. adcs sum, sum, td0
  57. tst len, #6
  58. bne .less8_wordlp
  59. .less8_byte: tst len, #1 @ odd number of bytes
  60. ldrneb td0, [buf], #1 @ include last byte
  61. adcnes sum, sum, td0, put_byte_0 @ update checksum
  62. .done: adc r0, sum, #0 @ collect up the last carry
  63. ldr td0, [sp], #4
  64. tst td0, #1 @ check buffer alignment
  65. movne r0, r0, ror #8 @ rotate checksum by 8 bits
  66. ldr pc, [sp], #4 @ return
  67. .not_aligned: tst buf, #1 @ odd address
  68. ldrneb td0, [buf], #1 @ make even
  69. subne len, len, #1
  70. adcnes sum, sum, td0, put_byte_1 @ update checksum
  71. tst buf, #2 @ 32-bit aligned?
  72. #if __LINUX_ARM_ARCH__ >= 4
  73. ldrneh td0, [buf], #2 @ make 32-bit aligned
  74. subne len, len, #2
  75. #else
  76. ldrneb td0, [buf], #1
  77. ldrneb ip, [buf], #1
  78. subne len, len, #2
  79. #ifndef __ARMEB__
  80. orrne td0, td0, ip, lsl #8
  81. #else
  82. orrne td0, ip, td0, lsl #8
  83. #endif
  84. #endif
  85. adcnes sum, sum, td0 @ update checksum
  86. mov pc, lr
  87. ENTRY(csum_partial)
  88. stmfd sp!, {buf, lr}
  89. cmp len, #8 @ Ensure that we have at least
  90. blo .less8 @ 8 bytes to copy.
  91. adds sum, sum, #0 @ C = 0
  92. tst buf, #3 @ Test destination alignment
  93. blne .not_aligned @ aligh 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 .less4
  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 .less4