162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 462306a36Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 562306a36Sopenharmony_ci * interface as the means of communication with the user level. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * IP/TCP/UDP checksumming routines 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Authors: Jorge Cwik, <jorge@laser.satlink.net> 1062306a36Sopenharmony_ci * Arnt Gulbrandsen, <agulbra@nvg.unit.no> 1162306a36Sopenharmony_ci * Tom May, <ftom@netcom.com> 1262306a36Sopenharmony_ci * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de> 1362306a36Sopenharmony_ci * Lots of code moved from tcp.c and ip.c; see those files 1462306a36Sopenharmony_ci * for more names. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: 1762306a36Sopenharmony_ci * Fixed some nasty bugs, causing some horrible crashes. 1862306a36Sopenharmony_ci * A: At some points, the sum (%0) was used as 1962306a36Sopenharmony_ci * length-counter instead of the length counter 2062306a36Sopenharmony_ci * (%1). Thanks to Roman Hodek for pointing this out. 2162306a36Sopenharmony_ci * B: GCC seems to mess up if one uses too many 2262306a36Sopenharmony_ci * data-registers to hold input values and one tries to 2362306a36Sopenharmony_ci * specify d0 and d1 as scratch registers. Letting gcc 2462306a36Sopenharmony_ci * choose these registers itself solves the problem. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * 1998/8/31 Andreas Schwab: 2762306a36Sopenharmony_ci * Zero out rest of buffer on exception in 2862306a36Sopenharmony_ci * csum_partial_copy_from_user. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/module.h> 3262306a36Sopenharmony_ci#include <net/checksum.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * computes a partial checksum, e.g. for TCP/UDP fragments 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci__wsum csum_partial(const void *buff, int len, __wsum sum) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci unsigned long tmp1, tmp2; 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * Experiments with ethernet and slip connections show that buff 4362306a36Sopenharmony_ci * is aligned on either a 2-byte or 4-byte boundary. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci __asm__("movel %2,%3\n\t" 4662306a36Sopenharmony_ci "btst #1,%3\n\t" /* Check alignment */ 4762306a36Sopenharmony_ci "jeq 2f\n\t" 4862306a36Sopenharmony_ci "subql #2,%1\n\t" /* buff%4==2: treat first word */ 4962306a36Sopenharmony_ci "jgt 1f\n\t" 5062306a36Sopenharmony_ci "addql #2,%1\n\t" /* len was == 2, treat only rest */ 5162306a36Sopenharmony_ci "jra 4f\n" 5262306a36Sopenharmony_ci "1:\t" 5362306a36Sopenharmony_ci "addw %2@+,%0\n\t" /* add first word to sum */ 5462306a36Sopenharmony_ci "clrl %3\n\t" 5562306a36Sopenharmony_ci "addxl %3,%0\n" /* add X bit */ 5662306a36Sopenharmony_ci "2:\t" 5762306a36Sopenharmony_ci /* unrolled loop for the main part: do 8 longs at once */ 5862306a36Sopenharmony_ci "movel %1,%3\n\t" /* save len in tmp1 */ 5962306a36Sopenharmony_ci "lsrl #5,%1\n\t" /* len/32 */ 6062306a36Sopenharmony_ci "jeq 2f\n\t" /* not enough... */ 6162306a36Sopenharmony_ci "subql #1,%1\n" 6262306a36Sopenharmony_ci "1:\t" 6362306a36Sopenharmony_ci "movel %2@+,%4\n\t" 6462306a36Sopenharmony_ci "addxl %4,%0\n\t" 6562306a36Sopenharmony_ci "movel %2@+,%4\n\t" 6662306a36Sopenharmony_ci "addxl %4,%0\n\t" 6762306a36Sopenharmony_ci "movel %2@+,%4\n\t" 6862306a36Sopenharmony_ci "addxl %4,%0\n\t" 6962306a36Sopenharmony_ci "movel %2@+,%4\n\t" 7062306a36Sopenharmony_ci "addxl %4,%0\n\t" 7162306a36Sopenharmony_ci "movel %2@+,%4\n\t" 7262306a36Sopenharmony_ci "addxl %4,%0\n\t" 7362306a36Sopenharmony_ci "movel %2@+,%4\n\t" 7462306a36Sopenharmony_ci "addxl %4,%0\n\t" 7562306a36Sopenharmony_ci "movel %2@+,%4\n\t" 7662306a36Sopenharmony_ci "addxl %4,%0\n\t" 7762306a36Sopenharmony_ci "movel %2@+,%4\n\t" 7862306a36Sopenharmony_ci "addxl %4,%0\n\t" 7962306a36Sopenharmony_ci "dbra %1,1b\n\t" 8062306a36Sopenharmony_ci "clrl %4\n\t" 8162306a36Sopenharmony_ci "addxl %4,%0\n\t" /* add X bit */ 8262306a36Sopenharmony_ci "clrw %1\n\t" 8362306a36Sopenharmony_ci "subql #1,%1\n\t" 8462306a36Sopenharmony_ci "jcc 1b\n" 8562306a36Sopenharmony_ci "2:\t" 8662306a36Sopenharmony_ci "movel %3,%1\n\t" /* restore len from tmp1 */ 8762306a36Sopenharmony_ci "andw #0x1c,%3\n\t" /* number of rest longs */ 8862306a36Sopenharmony_ci "jeq 4f\n\t" 8962306a36Sopenharmony_ci "lsrw #2,%3\n\t" 9062306a36Sopenharmony_ci "subqw #1,%3\n" 9162306a36Sopenharmony_ci "3:\t" 9262306a36Sopenharmony_ci /* loop for rest longs */ 9362306a36Sopenharmony_ci "movel %2@+,%4\n\t" 9462306a36Sopenharmony_ci "addxl %4,%0\n\t" 9562306a36Sopenharmony_ci "dbra %3,3b\n\t" 9662306a36Sopenharmony_ci "clrl %4\n\t" 9762306a36Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 9862306a36Sopenharmony_ci "4:\t" 9962306a36Sopenharmony_ci /* now check for rest bytes that do not fit into longs */ 10062306a36Sopenharmony_ci "andw #3,%1\n\t" 10162306a36Sopenharmony_ci "jeq 7f\n\t" 10262306a36Sopenharmony_ci "clrl %4\n\t" /* clear tmp2 for rest bytes */ 10362306a36Sopenharmony_ci "subqw #2,%1\n\t" 10462306a36Sopenharmony_ci "jlt 5f\n\t" 10562306a36Sopenharmony_ci "movew %2@+,%4\n\t" /* have rest >= 2: get word */ 10662306a36Sopenharmony_ci "swap %4\n\t" /* into bits 16..31 */ 10762306a36Sopenharmony_ci "tstw %1\n\t" /* another byte? */ 10862306a36Sopenharmony_ci "jeq 6f\n" 10962306a36Sopenharmony_ci "5:\t" 11062306a36Sopenharmony_ci "moveb %2@,%4\n\t" /* have odd rest: get byte */ 11162306a36Sopenharmony_ci "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */ 11262306a36Sopenharmony_ci "6:\t" 11362306a36Sopenharmony_ci "addl %4,%0\n\t" /* now add rest long to sum */ 11462306a36Sopenharmony_ci "clrl %4\n\t" 11562306a36Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 11662306a36Sopenharmony_ci "7:\t" 11762306a36Sopenharmony_ci : "=d" (sum), "=d" (len), "=a" (buff), 11862306a36Sopenharmony_ci "=&d" (tmp1), "=&d" (tmp2) 11962306a36Sopenharmony_ci : "0" (sum), "1" (len), "2" (buff) 12062306a36Sopenharmony_ci ); 12162306a36Sopenharmony_ci return(sum); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciEXPORT_SYMBOL(csum_partial); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* 12862306a36Sopenharmony_ci * copy from user space while checksumming, with exception handling. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci__wsum 13262306a36Sopenharmony_cicsum_and_copy_from_user(const void __user *src, void *dst, int len) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * GCC doesn't like more than 10 operands for the asm 13662306a36Sopenharmony_ci * statements so we have to use tmp2 for the error 13762306a36Sopenharmony_ci * code. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci unsigned long tmp1, tmp2; 14062306a36Sopenharmony_ci __wsum sum = ~0U; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci __asm__("movel %2,%4\n\t" 14362306a36Sopenharmony_ci "btst #1,%4\n\t" /* Check alignment */ 14462306a36Sopenharmony_ci "jeq 2f\n\t" 14562306a36Sopenharmony_ci "subql #2,%1\n\t" /* buff%4==2: treat first word */ 14662306a36Sopenharmony_ci "jgt 1f\n\t" 14762306a36Sopenharmony_ci "addql #2,%1\n\t" /* len was == 2, treat only rest */ 14862306a36Sopenharmony_ci "jra 4f\n" 14962306a36Sopenharmony_ci "1:\n" 15062306a36Sopenharmony_ci "10:\t" 15162306a36Sopenharmony_ci "movesw %2@+,%4\n\t" /* add first word to sum */ 15262306a36Sopenharmony_ci "addw %4,%0\n\t" 15362306a36Sopenharmony_ci "movew %4,%3@+\n\t" 15462306a36Sopenharmony_ci "clrl %4\n\t" 15562306a36Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 15662306a36Sopenharmony_ci "2:\t" 15762306a36Sopenharmony_ci /* unrolled loop for the main part: do 8 longs at once */ 15862306a36Sopenharmony_ci "movel %1,%4\n\t" /* save len in tmp1 */ 15962306a36Sopenharmony_ci "lsrl #5,%1\n\t" /* len/32 */ 16062306a36Sopenharmony_ci "jeq 2f\n\t" /* not enough... */ 16162306a36Sopenharmony_ci "subql #1,%1\n" 16262306a36Sopenharmony_ci "1:\n" 16362306a36Sopenharmony_ci "11:\t" 16462306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 16562306a36Sopenharmony_ci "addxl %5,%0\n\t" 16662306a36Sopenharmony_ci "movel %5,%3@+\n\t" 16762306a36Sopenharmony_ci "12:\t" 16862306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 16962306a36Sopenharmony_ci "addxl %5,%0\n\t" 17062306a36Sopenharmony_ci "movel %5,%3@+\n\t" 17162306a36Sopenharmony_ci "13:\t" 17262306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 17362306a36Sopenharmony_ci "addxl %5,%0\n\t" 17462306a36Sopenharmony_ci "movel %5,%3@+\n\t" 17562306a36Sopenharmony_ci "14:\t" 17662306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 17762306a36Sopenharmony_ci "addxl %5,%0\n\t" 17862306a36Sopenharmony_ci "movel %5,%3@+\n\t" 17962306a36Sopenharmony_ci "15:\t" 18062306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 18162306a36Sopenharmony_ci "addxl %5,%0\n\t" 18262306a36Sopenharmony_ci "movel %5,%3@+\n\t" 18362306a36Sopenharmony_ci "16:\t" 18462306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 18562306a36Sopenharmony_ci "addxl %5,%0\n\t" 18662306a36Sopenharmony_ci "movel %5,%3@+\n\t" 18762306a36Sopenharmony_ci "17:\t" 18862306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 18962306a36Sopenharmony_ci "addxl %5,%0\n\t" 19062306a36Sopenharmony_ci "movel %5,%3@+\n\t" 19162306a36Sopenharmony_ci "18:\t" 19262306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 19362306a36Sopenharmony_ci "addxl %5,%0\n\t" 19462306a36Sopenharmony_ci "movel %5,%3@+\n\t" 19562306a36Sopenharmony_ci "dbra %1,1b\n\t" 19662306a36Sopenharmony_ci "clrl %5\n\t" 19762306a36Sopenharmony_ci "addxl %5,%0\n\t" /* add X bit */ 19862306a36Sopenharmony_ci "clrw %1\n\t" 19962306a36Sopenharmony_ci "subql #1,%1\n\t" 20062306a36Sopenharmony_ci "jcc 1b\n" 20162306a36Sopenharmony_ci "2:\t" 20262306a36Sopenharmony_ci "movel %4,%1\n\t" /* restore len from tmp1 */ 20362306a36Sopenharmony_ci "andw #0x1c,%4\n\t" /* number of rest longs */ 20462306a36Sopenharmony_ci "jeq 4f\n\t" 20562306a36Sopenharmony_ci "lsrw #2,%4\n\t" 20662306a36Sopenharmony_ci "subqw #1,%4\n" 20762306a36Sopenharmony_ci "3:\n" 20862306a36Sopenharmony_ci /* loop for rest longs */ 20962306a36Sopenharmony_ci "19:\t" 21062306a36Sopenharmony_ci "movesl %2@+,%5\n\t" 21162306a36Sopenharmony_ci "addxl %5,%0\n\t" 21262306a36Sopenharmony_ci "movel %5,%3@+\n\t" 21362306a36Sopenharmony_ci "dbra %4,3b\n\t" 21462306a36Sopenharmony_ci "clrl %5\n\t" 21562306a36Sopenharmony_ci "addxl %5,%0\n" /* add X bit */ 21662306a36Sopenharmony_ci "4:\t" 21762306a36Sopenharmony_ci /* now check for rest bytes that do not fit into longs */ 21862306a36Sopenharmony_ci "andw #3,%1\n\t" 21962306a36Sopenharmony_ci "jeq 7f\n\t" 22062306a36Sopenharmony_ci "clrl %5\n\t" /* clear tmp2 for rest bytes */ 22162306a36Sopenharmony_ci "subqw #2,%1\n\t" 22262306a36Sopenharmony_ci "jlt 5f\n\t" 22362306a36Sopenharmony_ci "20:\t" 22462306a36Sopenharmony_ci "movesw %2@+,%5\n\t" /* have rest >= 2: get word */ 22562306a36Sopenharmony_ci "movew %5,%3@+\n\t" 22662306a36Sopenharmony_ci "swap %5\n\t" /* into bits 16..31 */ 22762306a36Sopenharmony_ci "tstw %1\n\t" /* another byte? */ 22862306a36Sopenharmony_ci "jeq 6f\n" 22962306a36Sopenharmony_ci "5:\n" 23062306a36Sopenharmony_ci "21:\t" 23162306a36Sopenharmony_ci "movesb %2@,%5\n\t" /* have odd rest: get byte */ 23262306a36Sopenharmony_ci "moveb %5,%3@+\n\t" 23362306a36Sopenharmony_ci "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */ 23462306a36Sopenharmony_ci "6:\t" 23562306a36Sopenharmony_ci "addl %5,%0\n\t" /* now add rest long to sum */ 23662306a36Sopenharmony_ci "clrl %5\n\t" 23762306a36Sopenharmony_ci "addxl %5,%0\n\t" /* add X bit */ 23862306a36Sopenharmony_ci "7:\t" 23962306a36Sopenharmony_ci ".section .fixup,\"ax\"\n" 24062306a36Sopenharmony_ci ".even\n" 24162306a36Sopenharmony_ci /* If any exception occurs, return 0 */ 24262306a36Sopenharmony_ci "90:\t" 24362306a36Sopenharmony_ci "clrl %0\n" 24462306a36Sopenharmony_ci "jra 7b\n" 24562306a36Sopenharmony_ci ".previous\n" 24662306a36Sopenharmony_ci ".section __ex_table,\"a\"\n" 24762306a36Sopenharmony_ci ".long 10b,90b\n" 24862306a36Sopenharmony_ci ".long 11b,90b\n" 24962306a36Sopenharmony_ci ".long 12b,90b\n" 25062306a36Sopenharmony_ci ".long 13b,90b\n" 25162306a36Sopenharmony_ci ".long 14b,90b\n" 25262306a36Sopenharmony_ci ".long 15b,90b\n" 25362306a36Sopenharmony_ci ".long 16b,90b\n" 25462306a36Sopenharmony_ci ".long 17b,90b\n" 25562306a36Sopenharmony_ci ".long 18b,90b\n" 25662306a36Sopenharmony_ci ".long 19b,90b\n" 25762306a36Sopenharmony_ci ".long 20b,90b\n" 25862306a36Sopenharmony_ci ".long 21b,90b\n" 25962306a36Sopenharmony_ci ".previous" 26062306a36Sopenharmony_ci : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), 26162306a36Sopenharmony_ci "=&d" (tmp1), "=d" (tmp2) 26262306a36Sopenharmony_ci : "0" (sum), "1" (len), "2" (src), "3" (dst) 26362306a36Sopenharmony_ci ); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return sum; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* 27062306a36Sopenharmony_ci * copy from kernel space while checksumming, otherwise like csum_partial 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci__wsum 27462306a36Sopenharmony_cicsum_partial_copy_nocheck(const void *src, void *dst, int len) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci unsigned long tmp1, tmp2; 27762306a36Sopenharmony_ci __wsum sum = 0; 27862306a36Sopenharmony_ci __asm__("movel %2,%4\n\t" 27962306a36Sopenharmony_ci "btst #1,%4\n\t" /* Check alignment */ 28062306a36Sopenharmony_ci "jeq 2f\n\t" 28162306a36Sopenharmony_ci "subql #2,%1\n\t" /* buff%4==2: treat first word */ 28262306a36Sopenharmony_ci "jgt 1f\n\t" 28362306a36Sopenharmony_ci "addql #2,%1\n\t" /* len was == 2, treat only rest */ 28462306a36Sopenharmony_ci "jra 4f\n" 28562306a36Sopenharmony_ci "1:\t" 28662306a36Sopenharmony_ci "movew %2@+,%4\n\t" /* add first word to sum */ 28762306a36Sopenharmony_ci "addw %4,%0\n\t" 28862306a36Sopenharmony_ci "movew %4,%3@+\n\t" 28962306a36Sopenharmony_ci "clrl %4\n\t" 29062306a36Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 29162306a36Sopenharmony_ci "2:\t" 29262306a36Sopenharmony_ci /* unrolled loop for the main part: do 8 longs at once */ 29362306a36Sopenharmony_ci "movel %1,%4\n\t" /* save len in tmp1 */ 29462306a36Sopenharmony_ci "lsrl #5,%1\n\t" /* len/32 */ 29562306a36Sopenharmony_ci "jeq 2f\n\t" /* not enough... */ 29662306a36Sopenharmony_ci "subql #1,%1\n" 29762306a36Sopenharmony_ci "1:\t" 29862306a36Sopenharmony_ci "movel %2@+,%5\n\t" 29962306a36Sopenharmony_ci "addxl %5,%0\n\t" 30062306a36Sopenharmony_ci "movel %5,%3@+\n\t" 30162306a36Sopenharmony_ci "movel %2@+,%5\n\t" 30262306a36Sopenharmony_ci "addxl %5,%0\n\t" 30362306a36Sopenharmony_ci "movel %5,%3@+\n\t" 30462306a36Sopenharmony_ci "movel %2@+,%5\n\t" 30562306a36Sopenharmony_ci "addxl %5,%0\n\t" 30662306a36Sopenharmony_ci "movel %5,%3@+\n\t" 30762306a36Sopenharmony_ci "movel %2@+,%5\n\t" 30862306a36Sopenharmony_ci "addxl %5,%0\n\t" 30962306a36Sopenharmony_ci "movel %5,%3@+\n\t" 31062306a36Sopenharmony_ci "movel %2@+,%5\n\t" 31162306a36Sopenharmony_ci "addxl %5,%0\n\t" 31262306a36Sopenharmony_ci "movel %5,%3@+\n\t" 31362306a36Sopenharmony_ci "movel %2@+,%5\n\t" 31462306a36Sopenharmony_ci "addxl %5,%0\n\t" 31562306a36Sopenharmony_ci "movel %5,%3@+\n\t" 31662306a36Sopenharmony_ci "movel %2@+,%5\n\t" 31762306a36Sopenharmony_ci "addxl %5,%0\n\t" 31862306a36Sopenharmony_ci "movel %5,%3@+\n\t" 31962306a36Sopenharmony_ci "movel %2@+,%5\n\t" 32062306a36Sopenharmony_ci "addxl %5,%0\n\t" 32162306a36Sopenharmony_ci "movel %5,%3@+\n\t" 32262306a36Sopenharmony_ci "dbra %1,1b\n\t" 32362306a36Sopenharmony_ci "clrl %5\n\t" 32462306a36Sopenharmony_ci "addxl %5,%0\n\t" /* add X bit */ 32562306a36Sopenharmony_ci "clrw %1\n\t" 32662306a36Sopenharmony_ci "subql #1,%1\n\t" 32762306a36Sopenharmony_ci "jcc 1b\n" 32862306a36Sopenharmony_ci "2:\t" 32962306a36Sopenharmony_ci "movel %4,%1\n\t" /* restore len from tmp1 */ 33062306a36Sopenharmony_ci "andw #0x1c,%4\n\t" /* number of rest longs */ 33162306a36Sopenharmony_ci "jeq 4f\n\t" 33262306a36Sopenharmony_ci "lsrw #2,%4\n\t" 33362306a36Sopenharmony_ci "subqw #1,%4\n" 33462306a36Sopenharmony_ci "3:\t" 33562306a36Sopenharmony_ci /* loop for rest longs */ 33662306a36Sopenharmony_ci "movel %2@+,%5\n\t" 33762306a36Sopenharmony_ci "addxl %5,%0\n\t" 33862306a36Sopenharmony_ci "movel %5,%3@+\n\t" 33962306a36Sopenharmony_ci "dbra %4,3b\n\t" 34062306a36Sopenharmony_ci "clrl %5\n\t" 34162306a36Sopenharmony_ci "addxl %5,%0\n" /* add X bit */ 34262306a36Sopenharmony_ci "4:\t" 34362306a36Sopenharmony_ci /* now check for rest bytes that do not fit into longs */ 34462306a36Sopenharmony_ci "andw #3,%1\n\t" 34562306a36Sopenharmony_ci "jeq 7f\n\t" 34662306a36Sopenharmony_ci "clrl %5\n\t" /* clear tmp2 for rest bytes */ 34762306a36Sopenharmony_ci "subqw #2,%1\n\t" 34862306a36Sopenharmony_ci "jlt 5f\n\t" 34962306a36Sopenharmony_ci "movew %2@+,%5\n\t" /* have rest >= 2: get word */ 35062306a36Sopenharmony_ci "movew %5,%3@+\n\t" 35162306a36Sopenharmony_ci "swap %5\n\t" /* into bits 16..31 */ 35262306a36Sopenharmony_ci "tstw %1\n\t" /* another byte? */ 35362306a36Sopenharmony_ci "jeq 6f\n" 35462306a36Sopenharmony_ci "5:\t" 35562306a36Sopenharmony_ci "moveb %2@,%5\n\t" /* have odd rest: get byte */ 35662306a36Sopenharmony_ci "moveb %5,%3@+\n\t" 35762306a36Sopenharmony_ci "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ 35862306a36Sopenharmony_ci "6:\t" 35962306a36Sopenharmony_ci "addl %5,%0\n\t" /* now add rest long to sum */ 36062306a36Sopenharmony_ci "clrl %5\n\t" 36162306a36Sopenharmony_ci "addxl %5,%0\n" /* add X bit */ 36262306a36Sopenharmony_ci "7:\t" 36362306a36Sopenharmony_ci : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), 36462306a36Sopenharmony_ci "=&d" (tmp1), "=&d" (tmp2) 36562306a36Sopenharmony_ci : "0" (sum), "1" (len), "2" (src), "3" (dst) 36662306a36Sopenharmony_ci ); 36762306a36Sopenharmony_ci return(sum); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ciEXPORT_SYMBOL(csum_partial_copy_nocheck); 370