2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER );
29 #include <ipxe/tcpip.h>
31 extern char x86_tcpip_loop_end[];
34 * Calculate continued TCP/IP checkum
36 * @v partial Checksum of already-summed data, in network byte order
38 * @v len Length of data buffer
39 * @ret cksum Updated checksum, in network byte order
41 uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
42 const void *data, size_t len ) {
43 unsigned long sum = ( ( ~partial ) & 0xffff );
44 unsigned long initial_word_count;
45 unsigned long loop_count;
46 unsigned long loop_partial_count;
47 unsigned long final_word_count;
48 unsigned long final_byte;
49 unsigned long discard_S;
50 unsigned long discard_c;
51 unsigned long discard_a;
52 unsigned long discard_r1;
53 unsigned long discard_r2;
55 /* Calculate number of initial 16-bit words required to bring
56 * the main loop into alignment. (We don't care about the
57 * speed for data aligned to less than 16 bits, since this
58 * situation won't occur in practice.)
60 if ( len >= sizeof ( sum ) ) {
61 initial_word_count = ( ( -( ( intptr_t ) data ) &
62 ( sizeof ( sum ) - 1 ) ) >> 1 );
64 initial_word_count = 0;
66 len -= ( initial_word_count * 2 );
68 /* Calculate number of iterations of the main loop. This loop
69 * processes native machine words (32-bit or 64-bit), and is
70 * unrolled 16 times. We calculate an overall iteration
71 * count, and a starting point for the first iteration.
73 loop_count = ( len / ( sizeof ( sum ) * 16 ) );
75 ( ( len % ( sizeof ( sum ) * 16 ) ) / sizeof ( sum ) );
77 /* Calculate number of 16-bit words remaining after the main
80 final_word_count = ( ( len % sizeof ( sum ) ) / 2 );
82 /* Calculate whether or not a final byte remains at the end */
83 final_byte = ( len & 1 );
85 /* Calculate the checksum */
86 __asm__ ( /* Calculate position at which to jump into the
89 "imul $( -x86_tcpip_loop_step_size ), %4\n\t"
92 /* Clear carry flag before starting checksumming */
95 /* Checksum initial words */
103 /* Main "lods;adc" loop, unrolled x16 */
106 "\nx86_tcpip_loop_start:\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 "lods%z2\n\tadc %2, %0\n\t"
115 "lods%z2\n\tadc %2, %0\n\t"
116 "lods%z2\n\tadc %2, %0\n\t"
117 "lods%z2\n\tadc %2, %0\n\t"
118 "lods%z2\n\tadc %2, %0\n\t"
119 "lods%z2\n\tadc %2, %0\n\t"
120 "lods%z2\n\tadc %2, %0\n\t"
121 "lods%z2\n\tadc %2, %0\n\t"
122 "lods%z2\n\tadc %2, %0\n\t"
123 "\nx86_tcpip_loop_end:\n\t"
124 "loop x86_tcpip_loop_start\n\t"
125 ".equ x86_tcpip_loop_step_size, "
126 " ( ( x86_tcpip_loop_end - x86_tcpip_loop_start ) >> 4 )\n\t"
128 /* Checksum remaining whole words */
137 /* Checksum final byte if applicable */
144 /* Fold down to a uint16_t */
149 #if ULONG_MAX > 0xffffffffUL /* 64-bit only */
154 #endif /* 64-bit only */
160 : "=&Q" ( sum ), "=&S" ( discard_S ), "=&a" ( discard_a ),
161 "=&c" ( discard_c ), "=&r" ( discard_r1 ),
163 : "0" ( sum ), "1" ( data ), "2" ( 0 ),
164 "3" ( initial_word_count + 1 ), "4" ( loop_partial_count ),
165 "5" ( x86_tcpip_loop_end ), "g" ( loop_count + 1 ),
166 "g" ( final_word_count + 1 ), "g" ( final_byte ) );
168 return ( ~sum & 0xffff );