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