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