Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

x86_tcpip.c 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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. FILE_LICENCE ( GPL2_OR_LATER );
  20. /** @file
  21. *
  22. * TCP/IP checksum
  23. *
  24. */
  25. #include <limits.h>
  26. #include <ipxe/tcpip.h>
  27. extern char x86_tcpip_loop_end[];
  28. /**
  29. * Calculate continued TCP/IP checkum
  30. *
  31. * @v partial Checksum of already-summed data, in network byte order
  32. * @v data Data buffer
  33. * @v len Length of data buffer
  34. * @ret cksum Updated checksum, in network byte order
  35. */
  36. uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
  37. const void *data, size_t len ) {
  38. unsigned long sum = ( ( ~partial ) & 0xffff );
  39. unsigned long initial_word_count;
  40. unsigned long loop_count;
  41. unsigned long loop_partial_count;
  42. unsigned long final_word_count;
  43. unsigned long final_byte;
  44. unsigned long discard_S;
  45. unsigned long discard_c;
  46. unsigned long discard_a;
  47. unsigned long discard_r1;
  48. unsigned long discard_r2;
  49. /* Calculate number of initial 16-bit words required to bring
  50. * the main loop into alignment. (We don't care about the
  51. * speed for data aligned to less than 16 bits, since this
  52. * situation won't occur in practice.)
  53. */
  54. if ( len >= sizeof ( sum ) ) {
  55. initial_word_count = ( ( -( ( intptr_t ) data ) &
  56. ( sizeof ( sum ) - 1 ) ) >> 1 );
  57. } else {
  58. initial_word_count = 0;
  59. }
  60. len -= ( initial_word_count * 2 );
  61. /* Calculate number of iterations of the main loop. This loop
  62. * processes native machine words (32-bit or 64-bit), and is
  63. * unrolled 16 times. We calculate an overall iteration
  64. * count, and a starting point for the first iteration.
  65. */
  66. loop_count = ( len / ( sizeof ( sum ) * 16 ) );
  67. loop_partial_count =
  68. ( ( len % ( sizeof ( sum ) * 16 ) ) / sizeof ( sum ) );
  69. /* Calculate number of 16-bit words remaining after the main
  70. * loop completes.
  71. */
  72. final_word_count = ( ( len % sizeof ( sum ) ) / 2 );
  73. /* Calculate whether or not a final byte remains at the end */
  74. final_byte = ( len & 1 );
  75. /* Calculate the checksum */
  76. __asm__ ( /* Calculate position at which to jump into the
  77. * unrolled loop.
  78. */
  79. "imul $( -x86_tcpip_loop_step_size ), %4\n\t"
  80. "add %5, %4\n\t"
  81. /* Clear carry flag before starting checksumming */
  82. "clc\n\t"
  83. /* Checksum initial words */
  84. "jmp 2f\n\t"
  85. "\n1:\n\t"
  86. "lodsw\n\t"
  87. "adcw %w2, %w0\n\t"
  88. "\n2:\n\t"
  89. "loop 1b\n\t"
  90. /* Main "lods;adc" loop, unrolled x16 */
  91. "mov %12, %3\n\t"
  92. "jmp *%4\n\t"
  93. "\nx86_tcpip_loop_start:\n\t"
  94. "lods%z2\n\tadc %2, %0\n\t"
  95. "lods%z2\n\tadc %2, %0\n\t"
  96. "lods%z2\n\tadc %2, %0\n\t"
  97. "lods%z2\n\tadc %2, %0\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. "\nx86_tcpip_loop_end:\n\t"
  111. "loop x86_tcpip_loop_start\n\t"
  112. ".equ x86_tcpip_loop_step_size, "
  113. " ( ( x86_tcpip_loop_end - x86_tcpip_loop_start ) >> 4 )\n\t"
  114. /* Checksum remaining whole words */
  115. "mov %13, %3\n\t"
  116. "jmp 2f\n\t"
  117. "\n1:\n\t"
  118. "lodsw\n\t"
  119. "adcw %w2, %w0\n\t"
  120. "\n2:\n\t"
  121. "loop 1b\n\t"
  122. /* Checksum final byte if applicable */
  123. "mov %14, %3\n\t"
  124. "loop 1f\n\t"
  125. "adcb (%1), %b0\n\t"
  126. "adcb $0, %h0\n\t"
  127. "\n1:\n\t"
  128. /* Fold down to a uint16_t */
  129. "push %0\n\t"
  130. "popw %w0\n\t"
  131. "popw %w2\n\t"
  132. "adcw %w2, %w0\n\t"
  133. #if ULONG_MAX > 0xffffffffUL /* 64-bit only */
  134. "popw %w2\n\t"
  135. "adcw %w2, %w0\n\t"
  136. "popw %w2\n\t"
  137. "adcw %w2, %w0\n\t"
  138. #endif /* 64-bit only */
  139. /* Consume CF */
  140. "adcw $0, %w0\n\t"
  141. "adcw $0, %w0\n\t"
  142. : "=&Q" ( sum ), "=&S" ( discard_S ), "=&a" ( discard_a ),
  143. "=&c" ( discard_c ), "=&r" ( discard_r1 ),
  144. "=&r" ( discard_r2 )
  145. : "0" ( sum ), "1" ( data ), "2" ( 0 ),
  146. "3" ( initial_word_count + 1 ), "4" ( loop_partial_count ),
  147. "5" ( x86_tcpip_loop_end ), "g" ( loop_count + 1 ),
  148. "g" ( final_word_count + 1 ), "g" ( final_byte ) );
  149. return ( ~sum & 0xffff );
  150. }