Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
5f7901a4 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
5f7901a4 MK |
5 | * Redistribution and use in source and binary forms are permitted |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
11 | * | |
12 | * @(#)in_cksum.c 7.2 (Berkeley) %G% | |
da7c5cc6 | 13 | */ |
51041fae | 14 | |
1884f3f6 JB |
15 | #include "types.h" |
16 | #include "mbuf.h" | |
51041fae BJ |
17 | |
18 | /* | |
e1cdb8f4 SL |
19 | * Checksum routine for Internet Protocol family headers (VAX Version). |
20 | * | |
2b4b57cd | 21 | * This routine is very heavily used in the network |
9a480eec | 22 | * code and should be modified for each CPU to be as fast as possible. |
51041fae | 23 | */ |
51041fae | 24 | |
8a13b737 | 25 | in_cksum(m, len) |
51041fae BJ |
26 | register struct mbuf *m; |
27 | register int len; | |
28 | { | |
9a480eec BJ |
29 | register u_short *w; /* on vax, known to be r9 */ |
30 | register int sum = 0; /* on vax, known to be r8 */ | |
51041fae | 31 | register int mlen = 0; |
51041fae BJ |
32 | |
33 | for (;;) { | |
2b4b57cd BJ |
34 | /* |
35 | * Each trip around loop adds in | |
36 | * word from one mbuf segment. | |
37 | */ | |
38 | w = mtod(m, u_short *); | |
51041fae | 39 | if (mlen == -1) { |
2b4b57cd BJ |
40 | /* |
41 | * There is a byte left from the last segment; | |
42 | * add it into the checksum. Don't have to worry | |
43 | * about a carry-out here because we make sure | |
44 | * that high part of (32 bit) sum is small below. | |
45 | */ | |
51041fae | 46 | sum += *(u_char *)w << 8; |
e6dd2097 | 47 | w = (u_short *)((char *)w + 1); |
51041fae BJ |
48 | mlen = m->m_len - 1; |
49 | len--; | |
50 | } else | |
51 | mlen = m->m_len; | |
52 | m = m->m_next; | |
53 | if (len < mlen) | |
54 | mlen = len; | |
55 | len -= mlen; | |
2b4b57cd BJ |
56 | /* |
57 | * Force to long boundary so we do longword aligned | |
58 | * memory operations. It is too hard to do byte | |
59 | * adjustment, do only word adjustment. | |
60 | */ | |
61 | if (((int)w&0x2) && mlen >= 2) { | |
62 | sum += *w++; | |
63 | mlen -= 2; | |
64 | } | |
65 | /* | |
66 | * Do as much of the checksum as possible 32 bits at at time. | |
67 | * In fact, this loop is unrolled to make overhead from | |
68 | * branches &c small. | |
69 | * | |
70 | * We can do a 16 bit ones complement sum 32 bits at a time | |
71 | * because the 32 bit register is acting as two 16 bit | |
72 | * registers for adding, with carries from the low added | |
73 | * into the high (by normal carry-chaining) and carries | |
74 | * from the high carried into the low on the next word | |
75 | * by use of the adwc instruction. This lets us run | |
76 | * this loop at almost memory speed. | |
77 | * | |
78 | * Here there is the danger of high order carry out, and | |
79 | * we carefully use adwc. | |
80 | */ | |
51041fae | 81 | while ((mlen -= 32) >= 0) { |
4d0a6cbd | 82 | #undef ADD |
1fd3f510 MK |
83 | #ifdef unneeded /* The loop construct clears carry for us... */ |
84 | asm("bicpsr $1"); /* clears carry */ | |
85 | #endif | |
4d0a6cbd | 86 | #define ADD asm("adwc (r9)+,r8;"); |
51041fae | 87 | ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; |
4d0a6cbd | 88 | asm("adwc $0,r8"); |
51041fae BJ |
89 | } |
90 | mlen += 32; | |
91 | while ((mlen -= 8) >= 0) { | |
1fd3f510 MK |
92 | #ifdef unneeded /* The loop construct clears carry for us... */ |
93 | asm("bicpsr $1"); /* clears carry */ | |
94 | #endif | |
4d0a6cbd BJ |
95 | ADD; ADD; |
96 | asm("adwc $0,r8"); | |
51041fae BJ |
97 | } |
98 | mlen += 8; | |
2b4b57cd BJ |
99 | /* |
100 | * Now eliminate the possibility of carry-out's by | |
101 | * folding back to a 16 bit number (adding high and | |
102 | * low parts together.) Then mop up trailing words | |
103 | * and maybe an odd byte. | |
104 | */ | |
105 | { asm("ashl $-16,r8,r0; addw2 r0,r8"); | |
106 | asm("adwc $0,r8; movzwl r8,r8"); } | |
51041fae | 107 | while ((mlen -= 2) >= 0) { |
2b4b57cd | 108 | asm("movzwl (r9)+,r0; addl2 r0,r8"); |
51041fae | 109 | } |
9a480eec | 110 | if (mlen == -1) { |
51041fae | 111 | sum += *(u_char *)w; |
9a480eec | 112 | } |
51041fae BJ |
113 | if (len == 0) |
114 | break; | |
2b4b57cd BJ |
115 | /* |
116 | * Locate the next block with some data. | |
117 | * If there is a word split across a boundary we | |
118 | * will wrap to the top with mlen == -1 and | |
119 | * then add it in shifted appropriately. | |
120 | */ | |
51041fae | 121 | for (;;) { |
f248b7ed | 122 | if (m == 0) { |
e6dd2097 | 123 | printf("cksum: out of data\n"); |
f248b7ed BJ |
124 | goto done; |
125 | } | |
51041fae BJ |
126 | if (m->m_len) |
127 | break; | |
128 | m = m->m_next; | |
129 | } | |
130 | } | |
f248b7ed | 131 | done: |
2b4b57cd BJ |
132 | /* |
133 | * Add together high and low parts of sum | |
134 | * and carry to get cksum. | |
135 | * Have to be careful to not drop the last | |
136 | * carry here. | |
137 | */ | |
e6dd2097 BJ |
138 | { asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8"); |
139 | asm("mcoml r8,r8; movzwl r8,r8"); } | |
140 | return (sum); | |
51041fae | 141 | } |