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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/** @file
28 *
29 * TCP/IP checksum
30 *
31 */
32
33#include <limits.h>
34#include <ipxe/tcpip.h>
35
36extern 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
unsigned long intptr_t
Definition stdint.h:21
long discard_c
Definition bigint.h:33
void * discard_S
Definition bigint.h:66
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Transport-network layer interface.
#define ULONG_MAX
Definition limits.h:50
__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")
char x86_tcpip_loop_end[]
uint16_t tcpip_continue_chksum(uint16_t partial, const void *data, size_t len)
Calculate continued TCP/IP checkum.
Definition x86_tcpip.c:46