iPXE
x86_tcpip.c
Go to the documentation of this file.
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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 /** @file
28  *
29  * TCP/IP checksum
30  *
31  */
32 
33 #include <limits.h>
34 #include <ipxe/tcpip.h>
35 
36 extern char x86_tcpip_loop_end[];
37 
38 /**
39  * Calculate continued TCP/IP checkum
40  *
41  * @v partial Checksum of already-summed data, in network byte order
42  * @v data Data buffer
43  * @v len Length of data buffer
44  * @ret cksum Updated checksum, in network byte order
45  */
47  size_t len ) {
48  unsigned long sum = ( ( ~partial ) & 0xffff );
49  unsigned long initial_word_count;
50  unsigned long loop_count;
51  unsigned long loop_partial_count;
52  unsigned long final_word_count;
53  unsigned long final_byte;
54  unsigned long discard_S;
55  unsigned long discard_c;
56  unsigned long discard_a;
57  unsigned long discard_r1;
58  unsigned long discard_r2;
59 
60  /* Calculate number of initial 16-bit words required to bring
61  * the main loop into alignment. (We don't care about the
62  * speed for data aligned to less than 16 bits, since this
63  * situation won't occur in practice.)
64  */
65  if ( len >= sizeof ( sum ) ) {
66  initial_word_count = ( ( -( ( intptr_t ) data ) &
67  ( sizeof ( sum ) - 1 ) ) >> 1 );
68  } else {
69  initial_word_count = 0;
70  }
71  len -= ( initial_word_count * 2 );
72 
73  /* Calculate number of iterations of the main loop. This loop
74  * processes native machine words (32-bit or 64-bit), and is
75  * unrolled 16 times. We calculate an overall iteration
76  * count, and a starting point for the first iteration.
77  */
78  loop_count = ( len / ( sizeof ( sum ) * 16 ) );
79  loop_partial_count =
80  ( ( len % ( sizeof ( sum ) * 16 ) ) / sizeof ( sum ) );
81 
82  /* Calculate number of 16-bit words remaining after the main
83  * loop completes.
84  */
85  final_word_count = ( ( len % sizeof ( sum ) ) / 2 );
86 
87  /* Calculate whether or not a final byte remains at the end */
88  final_byte = ( len & 1 );
89 
90  /* Calculate the checksum */
91  __asm__ ( /* Calculate position at which to jump into the
92  * unrolled loop.
93  */
94  "imul $( -x86_tcpip_loop_step_size ), %4\n\t"
95  "add %5, %4\n\t"
96 
97  /* Clear carry flag before starting checksumming */
98  "clc\n\t"
99 
100  /* Checksum initial words */
101  "jmp 2f\n\t"
102  "\n1:\n\t"
103  "lodsw\n\t"
104  "adcw %w2, %w0\n\t"
105  "\n2:\n\t"
106  "loop 1b\n\t"
107 
108  /* Main "lods;adc" loop, unrolled x16 */
109  "mov %12, %3\n\t"
110  "jmp *%4\n\t"
111  "\nx86_tcpip_loop_start:\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  "lods%z2\n\tadc %2, %0\n\t"
124  "lods%z2\n\tadc %2, %0\n\t"
125  "lods%z2\n\tadc %2, %0\n\t"
126  "lods%z2\n\tadc %2, %0\n\t"
127  "lods%z2\n\tadc %2, %0\n\t"
128  "\nx86_tcpip_loop_end:\n\t"
129  "loop x86_tcpip_loop_start\n\t"
130  ".equ x86_tcpip_loop_step_size, "
131  " ( ( x86_tcpip_loop_end - x86_tcpip_loop_start ) >> 4 )\n\t"
132 
133  /* Checksum remaining whole words */
134  "mov %13, %3\n\t"
135  "jmp 2f\n\t"
136  "\n1:\n\t"
137  "lodsw\n\t"
138  "adcw %w2, %w0\n\t"
139  "\n2:\n\t"
140  "loop 1b\n\t"
141 
142  /* Checksum final byte if applicable */
143  "mov %14, %3\n\t"
144  "loop 1f\n\t"
145  "adcb (%1), %b0\n\t"
146  "adcb $0, %h0\n\t"
147  "\n1:\n\t"
148 
149  /* Fold down to a uint16_t */
150  "push %0\n\t"
151  "popw %w0\n\t"
152  "popw %w2\n\t"
153  "adcw %w2, %w0\n\t"
154 #if ULONG_MAX > 0xffffffffUL /* 64-bit only */
155  "popw %w2\n\t"
156  "adcw %w2, %w0\n\t"
157  "popw %w2\n\t"
158  "adcw %w2, %w0\n\t"
159 #endif /* 64-bit only */
160 
161  /* Consume CF */
162  "adcw $0, %w0\n\t"
163  "adcw $0, %w0\n\t"
164 
165  : "=&Q" ( sum ), "=&S" ( discard_S ), "=&a" ( discard_a ),
166  "=&c" ( discard_c ), "=&r" ( discard_r1 ),
167  "=&r" ( discard_r2 )
168  : "0" ( sum ), "1" ( data ), "2" ( 0 ),
169  "3" ( initial_word_count + 1 ), "4" ( loop_partial_count ),
170  "5" ( x86_tcpip_loop_end ), "g" ( loop_count + 1 ),
171  "g" ( final_word_count + 1 ), "g" ( final_byte ) );
172 
173  return ( ~sum & 0xffff );
174 }
unsigned short uint16_t
Definition: stdint.h:11
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void * discard_S
Definition: bigint.h:66
FILE_SECBOOT(PERMITTED)
unsigned long intptr_t
Definition: stdint.h:21
char x86_tcpip_loop_end[]
ring len
Length.
Definition: dwmac.h:231
Transport-network layer interface.
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
uint8_t data[48]
Additional event data.
Definition: ena.h:22
long discard_c
Definition: bigint.h:33
#define ULONG_MAX
Definition: limits.h:50
uint16_t tcpip_continue_chksum(uint16_t partial, const void *data, size_t len)
Calculate continued TCP/IP checkum.
Definition: x86_tcpip.c:46