1 /* in_cksum.c 1.11 81/11/26 */ 2 3 #include <sys/types.h> 4 #include "../h/mbuf.h" 5 #include "../net/in.h" 6 #include "../net/in_systm.h" 7 8 /* 9 * Checksum routine for Internet Protocol family headers. 10 * This routine is very heavily used in the network 11 * code and should be rewritten for each CPU to be as fast as possible. 12 */ 13 14 #if vax 15 in_cksum(m, len) 16 register struct mbuf *m; 17 register int len; 18 { 19 register u_short *w; /* known to be r9 */ 20 register int sum = 0; /* known to be r8 */ 21 register int mlen = 0; 22 COUNT(IN_CKSUM); 23 24 for (;;) { 25 /* 26 * Each trip around loop adds in 27 * word from one mbuf segment. 28 */ 29 w = mtod(m, u_short *); 30 if (mlen == -1) { 31 /* 32 * There is a byte left from the last segment; 33 * add it into the checksum. Don't have to worry 34 * about a carry-out here because we make sure 35 * that high part of (32 bit) sum is small below. 36 */ 37 sum += *(u_char *)w << 8; 38 w = (u_short *)((char *)w + 1); 39 mlen = m->m_len - 1; 40 len--; 41 } else 42 mlen = m->m_len; 43 m = m->m_next; 44 if (len < mlen) 45 mlen = len; 46 len -= mlen; 47 /* 48 * Force to long boundary so we do longword aligned 49 * memory operations. It is too hard to do byte 50 * adjustment, do only word adjustment. 51 */ 52 if (((int)w&0x2) && mlen >= 2) { 53 sum += *w++; 54 mlen -= 2; 55 } 56 /* 57 * Do as much of the checksum as possible 32 bits at at time. 58 * In fact, this loop is unrolled to make overhead from 59 * branches &c small. 60 * 61 * We can do a 16 bit ones complement sum 32 bits at a time 62 * because the 32 bit register is acting as two 16 bit 63 * registers for adding, with carries from the low added 64 * into the high (by normal carry-chaining) and carries 65 * from the high carried into the low on the next word 66 * by use of the adwc instruction. This lets us run 67 * this loop at almost memory speed. 68 * 69 * Here there is the danger of high order carry out, and 70 * we carefully use adwc. 71 */ 72 while ((mlen -= 32) >= 0) { 73 asm("clrl r0"); /* clears carry */ 74 #undef ADD 75 #define ADD asm("adwc (r9)+,r8;"); 76 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; 77 asm("adwc $0,r8"); 78 } 79 mlen += 32; 80 while ((mlen -= 8) >= 0) { 81 asm("clrl r0"); 82 ADD; ADD; 83 asm("adwc $0,r8"); 84 } 85 mlen += 8; 86 /* 87 * Now eliminate the possibility of carry-out's by 88 * folding back to a 16 bit number (adding high and 89 * low parts together.) Then mop up trailing words 90 * and maybe an odd byte. 91 */ 92 { asm("ashl $-16,r8,r0; addw2 r0,r8"); 93 asm("adwc $0,r8; movzwl r8,r8"); } 94 while ((mlen -= 2) >= 0) { 95 asm("movzwl (r9)+,r0; addl2 r0,r8"); 96 } 97 if (mlen == -1) 98 sum += *(u_char *)w; 99 if (len == 0) 100 break; 101 /* 102 * Locate the next block with some data. 103 * If there is a word split across a boundary we 104 * will wrap to the top with mlen == -1 and 105 * then add it in shifted appropriately. 106 */ 107 for (;;) { 108 if (m == 0) { 109 printf("cksum: out of data\n"); 110 goto done; 111 } 112 if (m->m_len) 113 break; 114 m = m->m_next; 115 } 116 } 117 done: 118 /* 119 * Add together high and low parts of sum 120 * and carry to get cksum. 121 * Have to be careful to not drop the last 122 * carry here. 123 */ 124 { asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8"); 125 asm("mcoml r8,r8; movzwl r8,r8"); } 126 return (sum); 127 } 128 #endif 129