Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
9.0 KiB

  1. title "Compute Checksum"
  2. ;
  3. ; Copyright (c) 1985-2000 Microsoft Corporation
  4. ; This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  5. ; You should have received a copy of the Microsoft End-User License Agreement
  6. ; for this software along with this release; see the file "license.txt".
  7. ; If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  8. ; or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements a function to compute the checksum of a buffer.
  13. ;
  14. ; Environment:
  15. ;
  16. ; Any mode.
  17. ;
  18. LOOP_UNROLLING_BITS equ 5
  19. LOOP_UNROLLING equ (1 SHL LOOP_UNROLLING_BITS)
  20. .386
  21. .model small,c
  22. assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
  23. assume fs:nothing,gs:nothing
  24. .xlist
  25. include callconv.inc
  26. .list
  27. .code
  28. ;++
  29. ;
  30. ; ULONG
  31. ; tcpxsum(
  32. ; IN ULONG cksum,
  33. ; IN PUCHAR buf,
  34. ; IN ULONG len
  35. ; )
  36. ;
  37. ; Routine Description:
  38. ;
  39. ; This function computes the checksum of the specified buffer.
  40. ;
  41. ; Arguments:
  42. ;
  43. ; cksum - Suppiles the initial checksum value, in 16-bit form,
  44. ; with the high word set to 0.
  45. ;
  46. ; buf - Supplies a pointer to the buffer to the checksum buffer.
  47. ;
  48. ; len - Supplies the length of the buffer in bytes.
  49. ;
  50. ; Return Value:
  51. ;
  52. ; The computed checksum in 32-bit two-partial-accumulators form, added to
  53. ; the initial checksum, is returned as the function value.
  54. ;
  55. ;--
  56. cksum equ 12 ; stack offset to initial checksum
  57. buf equ 16 ; stack offset to source address
  58. len equ 20 ; stack offset to length in words
  59. to_checksum_last_word:
  60. jmp checksum_last_word
  61. to_checksum_done:
  62. jmp checksum_done
  63. to_checksum_dword_loop_done:
  64. jmp checksum_dword_loop_done
  65. cPublicProc tcpxsum,3
  66. push ebx ; save nonvolatile register
  67. push esi ; save nonvolatile register
  68. mov ecx,[esp + len] ; get length in bytes
  69. sub eax,eax ; clear computed checksum
  70. test ecx,ecx ; any bytes to checksum at all?
  71. jz short to_checksum_done ; no bytes to checksum
  72. ;
  73. ; if the checksum buffer is not word aligned, then add the first byte of
  74. ; the buffer to the input checksum.
  75. ;
  76. mov esi,[esp + buf] ; get source address
  77. sub edx,edx ; set up to load word into EDX below
  78. test esi,1 ; check if buffer word aligned
  79. jz short checksum_word_aligned ; if zf, buffer word aligned
  80. mov ah,[esi] ; get first byte (we know we'll have
  81. ; to swap at the end)
  82. inc esi ; increment buffer address
  83. dec ecx ; decrement number of bytes
  84. jz short to_checksum_done ; if zf set, no more bytes
  85. ;
  86. ; If the buffer is not an even number of of bytes, then initialize
  87. ; the computed checksum with the last byte of the buffer.
  88. ;
  89. checksum_word_aligned: ;
  90. shr ecx,1 ; convert to word count
  91. jnc short checksum_start ; if nc, even number of bytes
  92. mov al,[esi+ecx*2] ; initialize the computed checksum
  93. jz short to_checksum_done ; if zf set, no more bytes
  94. ;
  95. ; Compute checksum in large blocks of dwords, with one partial word up front if
  96. ; necessary to get dword alignment, and another partial word at the end if
  97. ; needed.
  98. ;
  99. ;
  100. ; Compute checksum on the leading word, if that's necessary to get dword
  101. ; alignment.
  102. ;
  103. checksum_start: ;
  104. test esi,02h ; check if source dword aligned
  105. jz short checksum_dword_aligned ; source is already dword aligned
  106. mov dx,[esi] ; get first word to checksum
  107. add esi,2 ; update source address
  108. add eax,edx ; update partial checksum
  109. ; (no carry is possible, because EAX
  110. ; and EDX are both 16-bit values)
  111. dec ecx ; count off this word (zero case gets
  112. ; picked up below)
  113. ;
  114. ; Checksum as many words as possible by processing a dword at a time.
  115. ;
  116. checksum_dword_aligned:
  117. push ecx ; so we can tell if there's a trailing
  118. ; word later
  119. shr ecx,1 ; # of dwords to checksum
  120. jz short to_checksum_last_word ; no dwords to checksum
  121. mov edx,[esi] ; preload the first dword
  122. add esi,4 ; point to the next dword
  123. dec ecx ; count off the dword we just loaded
  124. jz short to_checksum_dword_loop_done
  125. ; skip the loop if that was the only
  126. ; dword
  127. mov ebx,ecx ; EBX = # of dwords left to checksum
  128. add ecx,LOOP_UNROLLING-1 ; round up loop count
  129. shr ecx,LOOP_UNROLLING_BITS ; convert from word count to unrolled
  130. ; loop count
  131. and ebx,LOOP_UNROLLING-1 ; # of partial dwords to do in first
  132. ; loop
  133. jz short checksum_dword_loop ; special-case when no partial loop,
  134. ; because fixup below doesn't work
  135. ; in that case (carry flag is
  136. ; cleared at this point, as required
  137. ; at loop entry)
  138. lea esi,[esi+ebx*4-(LOOP_UNROLLING*4)]
  139. ; adjust buffer pointer back to
  140. ; compensate for hardwired displacement
  141. ; at loop entry point
  142. ; ***doesn't change carry flag***
  143. jmp loop_entry[ebx*4] ; enter the loop to do the first,
  144. ; partial iteration, after which we can
  145. ; just do 64-word blocks
  146. ; ***doesn't change carry flag***
  147. checksum_dword_loop:
  148. DEFLAB macro pre,suf
  149. pre&suf:
  150. endm
  151. TEMP=0
  152. REPT LOOP_UNROLLING
  153. deflab loop_entry_,%TEMP
  154. adc eax,edx
  155. mov edx,[esi + TEMP]
  156. TEMP=TEMP+4
  157. ENDM
  158. checksum_dword_loop_end:
  159. lea esi,[esi + LOOP_UNROLLING * 4] ; update source address
  160. ; ***doesn't change carry flag***
  161. dec ecx ; count off unrolled loop iteration
  162. ; ***doesn't change carry flag***
  163. jnz checksum_dword_loop ; do more blocks
  164. checksum_dword_loop_done label proc
  165. adc eax,edx ; finish dword checksum
  166. mov edx,0 ; prepare to load trailing word
  167. adc eax,edx
  168. ;
  169. ; Compute checksum on the trailing word, if there is one.
  170. ; High word of EDX = 0 at this point
  171. ; Carry flag set iff there's a trailing word to do at this point
  172. ;
  173. checksum_last_word label proc ; "proc" so not scoped to function
  174. pop ecx ; get back word count
  175. test ecx,1 ; is there a trailing word?
  176. jz short checksum_done ; no trailing word
  177. add ax,[esi] ; add in the trailing word
  178. adc eax,0 ;
  179. checksum_done label proc ; "proc" so not scoped to function
  180. mov ecx,eax ; fold the checksum to 16 bits
  181. ror ecx,16
  182. add eax,ecx
  183. mov ebx,[esp + buf]
  184. shr eax,16
  185. test ebx,1 ; check if buffer word aligned
  186. jz short checksum_combine ; if zf set, buffer word aligned
  187. ror ax,8 ; byte aligned--swap bytes back
  188. checksum_combine label proc ; "proc" so not scoped to function
  189. add ax,word ptr [esp + cksum] ; combine checksums
  190. pop esi ; restore nonvolatile register
  191. adc eax,0 ;
  192. pop ebx ; restore nonvolatile register
  193. stdRET tcpxsum
  194. REFLAB macro pre,suf
  195. dd pre&suf
  196. endm
  197. align 4
  198. loop_entry label dword
  199. dd 0
  200. TEMP=LOOP_UNROLLING*4
  201. REPT LOOP_UNROLLING-1
  202. TEMP=TEMP-4
  203. reflab loop_entry_,%TEMP
  204. ENDM
  205. stdENDP tcpxsum
  206. end