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.

x86_tcpip.c 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. /** @file
  25. *
  26. * TCP/IP checksum
  27. *
  28. */
  29. #include <limits.h>
  30. #include <ipxe/tcpip.h>
  31. extern char x86_tcpip_loop_end[];
  32. /**
  33. * Calculate continued TCP/IP checkum
  34. *
  35. * @v partial Checksum of already-summed data, in network byte order
  36. * @v data Data buffer
  37. * @v len Length of data buffer
  38. * @ret cksum Updated checksum, in network byte order
  39. */
  40. uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
  41. const void *data, size_t len ) {
  42. unsigned long sum = ( ( ~partial ) & 0xffff );
  43. unsigned long initial_word_count;
  44. unsigned long loop_count;
  45. unsigned long loop_partial_count;
  46. unsigned long final_word_count;
  47. unsigned long final_byte;
  48. unsigned long discard_S;
  49. unsigned long discard_c;
  50. unsigned long discard_a;
  51. unsigned long discard_r1;
  52. unsigned long discard_r2;
  53. /* Calculate number of initial 16-bit words required to bring
  54. * the main loop into alignment. (We don't care about the
  55. * speed for data aligned to less than 16 bits, since this
  56. * situation won't occur in practice.)
  57. */
  58. if ( len >= sizeof ( sum ) ) {
  59. initial_word_count = ( ( -( ( intptr_t ) data ) &
  60. ( sizeof ( sum ) - 1 ) ) >> 1 );
  61. } else {
  62. initial_word_count = 0;
  63. }
  64. len -= ( initial_word_count * 2 );
  65. /* Calculate number of iterations of the main loop. This loop
  66. * processes native machine words (32-bit or 64-bit), and is
  67. * unrolled 16 times. We calculate an overall iteration
  68. * count, and a starting point for the first iteration.
  69. */
  70. loop_count = ( len / ( sizeof ( sum ) * 16 ) );
  71. loop_partial_count =
  72. ( ( len % ( sizeof ( sum ) * 16 ) ) / sizeof ( sum ) );
  73. /* Calculate number of 16-bit words remaining after the main
  74. * loop completes.
  75. */
  76. final_word_count = ( ( len % sizeof ( sum ) ) / 2 );
  77. /* Calculate whether or not a final byte remains at the end */
  78. final_byte = ( len & 1 );
  79. /* Calculate the checksum */
  80. __asm__ ( /* Calculate position at which to jump into the
  81. * unrolled loop.
  82. */
  83. "imul $( -x86_tcpip_loop_step_size ), %4\n\t"
  84. "add %5, %4\n\t"
  85. /* Clear carry flag before starting checksumming */
  86. "clc\n\t"
  87. /* Checksum initial words */
  88. "jmp 2f\n\t"
  89. "\n1:\n\t"
  90. "lodsw\n\t"
  91. "adcw %w2, %w0\n\t"
  92. "\n2:\n\t"
  93. "loop 1b\n\t"
  94. /* Main "lods;adc" loop, unrolled x16 */
  95. "mov %12, %3\n\t"
  96. "jmp *%4\n\t"
  97. "\nx86_tcpip_loop_start:\n\t"
  98. "lods%z2\n\tadc %2, %0\n\t"
  99. "lods%z2\n\tadc %2, %0\n\t"
  100. "lods%z2\n\tadc %2, %0\n\t"
  101. "lods%z2\n\tadc %2, %0\n\t"
  102. "lods%z2\n\tadc %2, %0\n\t"
  103. "lods%z2\n\tadc %2, %0\n\t"
  104. "lods%z2\n\tadc %2, %0\n\t"
  105. "lods%z2\n\tadc %2, %0\n\t"
  106. "lods%z2\n\tadc %2, %0\n\t"
  107. "lods%z2\n\tadc %2, %0\n\t"
  108. "lods%z2\n\tadc %2, %0\n\t"
  109. "lods%z2\n\tadc %2, %0\n\t"
  110. "lods%z2\n\tadc %2, %0\n\t"
  111. "lods%z2\n\tadc %2, %0\n\t"
  112. "lods%z2\n\tadc %2, %0\n\t"
  113. "lods%z2\n\tadc %2, %0\n\t"
  114. "\nx86_tcpip_loop_end:\n\t"
  115. "loop x86_tcpip_loop_start\n\t"
  116. ".equ x86_tcpip_loop_step_size, "
  117. " ( ( x86_tcpip_loop_end - x86_tcpip_loop_start ) >> 4 )\n\t"
  118. /* Checksum remaining whole words */
  119. "mov %13, %3\n\t"
  120. "jmp 2f\n\t"
  121. "\n1:\n\t"
  122. "lodsw\n\t"
  123. "adcw %w2, %w0\n\t"
  124. "\n2:\n\t"
  125. "loop 1b\n\t"
  126. /* Checksum final byte if applicable */
  127. "mov %14, %3\n\t"
  128. "loop 1f\n\t"
  129. "adcb (%1), %b0\n\t"
  130. "adcb $0, %h0\n\t"
  131. "\n1:\n\t"
  132. /* Fold down to a uint16_t */
  133. "push %0\n\t"
  134. "popw %w0\n\t"
  135. "popw %w2\n\t"
  136. "adcw %w2, %w0\n\t"
  137. #if ULONG_MAX > 0xffffffffUL /* 64-bit only */
  138. "popw %w2\n\t"
  139. "adcw %w2, %w0\n\t"
  140. "popw %w2\n\t"
  141. "adcw %w2, %w0\n\t"
  142. #endif /* 64-bit only */
  143. /* Consume CF */
  144. "adcw $0, %w0\n\t"
  145. "adcw $0, %w0\n\t"
  146. : "=&Q" ( sum ), "=&S" ( discard_S ), "=&a" ( discard_a ),
  147. "=&c" ( discard_c ), "=&r" ( discard_r1 ),
  148. "=&r" ( discard_r2 )
  149. : "0" ( sum ), "1" ( data ), "2" ( 0 ),
  150. "3" ( initial_word_count + 1 ), "4" ( loop_partial_count ),
  151. "5" ( x86_tcpip_loop_end ), "g" ( loop_count + 1 ),
  152. "g" ( final_word_count + 1 ), "g" ( final_byte ) );
  153. return ( ~sum & 0xffff );
  154. }