1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 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) 03/29/88 13 */ 14 15 #include "types.h" 16 #include "mbuf.h" 17 18 /* 19 * Checksum routine for Internet Protocol family headers (VAX Version). 20 * 21 * This routine is very heavily used in the network 22 * code and should be modified for each CPU to be as fast as possible. 23 */ 24 25 in_cksum(m, len) 26 register struct mbuf *m; 27 register int len; 28 { 29 register u_short *w; /* on vax, known to be r9 */ 30 register int sum = 0; /* on vax, known to be r8 */ 31 register int mlen = 0; 32 33 for (;;) { 34 /* 35 * Each trip around loop adds in 36 * word from one mbuf segment. 37 */ 38 w = mtod(m, u_short *); 39 if (mlen == -1) { 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 */ 46 sum += *(u_char *)w << 8; 47 w = (u_short *)((char *)w + 1); 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; 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 */ 81 while ((mlen -= 32) >= 0) { 82 #undef ADD 83 #ifdef unneeded /* The loop construct clears carry for us... */ 84 asm("bicpsr $1"); /* clears carry */ 85 #endif 86 #define ADD asm("adwc (r9)+,r8;"); 87 ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD; 88 asm("adwc $0,r8"); 89 } 90 mlen += 32; 91 while ((mlen -= 8) >= 0) { 92 #ifdef unneeded /* The loop construct clears carry for us... */ 93 asm("bicpsr $1"); /* clears carry */ 94 #endif 95 ADD; ADD; 96 asm("adwc $0,r8"); 97 } 98 mlen += 8; 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"); } 107 while ((mlen -= 2) >= 0) { 108 asm("movzwl (r9)+,r0; addl2 r0,r8"); 109 } 110 if (mlen == -1) { 111 sum += *(u_char *)w; 112 } 113 if (len == 0) 114 break; 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 */ 121 for (;;) { 122 if (m == 0) { 123 printf("cksum: out of data\n"); 124 goto done; 125 } 126 if (m->m_len) 127 break; 128 m = m->m_next; 129 } 130 } 131 done: 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 */ 138 { asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8"); 139 asm("mcoml r8,r8; movzwl r8,r8"); } 140 return (sum); 141 } 142