18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 48c2ecf20Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 58c2ecf20Sopenharmony_ci * interface as the means of communication with the user level. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * IP/TCP/UDP checksumming routines 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Authors: Jorge Cwik, <jorge@laser.satlink.net> 108c2ecf20Sopenharmony_ci * Arnt Gulbrandsen, <agulbra@nvg.unit.no> 118c2ecf20Sopenharmony_ci * Tom May, <ftom@netcom.com> 128c2ecf20Sopenharmony_ci * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de> 138c2ecf20Sopenharmony_ci * Lots of code moved from tcp.c and ip.c; see those files 148c2ecf20Sopenharmony_ci * for more names. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: 178c2ecf20Sopenharmony_ci * Fixed some nasty bugs, causing some horrible crashes. 188c2ecf20Sopenharmony_ci * A: At some points, the sum (%0) was used as 198c2ecf20Sopenharmony_ci * length-counter instead of the length counter 208c2ecf20Sopenharmony_ci * (%1). Thanks to Roman Hodek for pointing this out. 218c2ecf20Sopenharmony_ci * B: GCC seems to mess up if one uses too many 228c2ecf20Sopenharmony_ci * data-registers to hold input values and one tries to 238c2ecf20Sopenharmony_ci * specify d0 and d1 as scratch registers. Letting gcc 248c2ecf20Sopenharmony_ci * choose these registers itself solves the problem. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * 1998/8/31 Andreas Schwab: 278c2ecf20Sopenharmony_ci * Zero out rest of buffer on exception in 288c2ecf20Sopenharmony_ci * csum_partial_copy_from_user. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/module.h> 328c2ecf20Sopenharmony_ci#include <net/checksum.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * computes a partial checksum, e.g. for TCP/UDP fragments 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci__wsum csum_partial(const void *buff, int len, __wsum sum) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci unsigned long tmp1, tmp2; 418c2ecf20Sopenharmony_ci /* 428c2ecf20Sopenharmony_ci * Experiments with ethernet and slip connections show that buff 438c2ecf20Sopenharmony_ci * is aligned on either a 2-byte or 4-byte boundary. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci __asm__("movel %2,%3\n\t" 468c2ecf20Sopenharmony_ci "btst #1,%3\n\t" /* Check alignment */ 478c2ecf20Sopenharmony_ci "jeq 2f\n\t" 488c2ecf20Sopenharmony_ci "subql #2,%1\n\t" /* buff%4==2: treat first word */ 498c2ecf20Sopenharmony_ci "jgt 1f\n\t" 508c2ecf20Sopenharmony_ci "addql #2,%1\n\t" /* len was == 2, treat only rest */ 518c2ecf20Sopenharmony_ci "jra 4f\n" 528c2ecf20Sopenharmony_ci "1:\t" 538c2ecf20Sopenharmony_ci "addw %2@+,%0\n\t" /* add first word to sum */ 548c2ecf20Sopenharmony_ci "clrl %3\n\t" 558c2ecf20Sopenharmony_ci "addxl %3,%0\n" /* add X bit */ 568c2ecf20Sopenharmony_ci "2:\t" 578c2ecf20Sopenharmony_ci /* unrolled loop for the main part: do 8 longs at once */ 588c2ecf20Sopenharmony_ci "movel %1,%3\n\t" /* save len in tmp1 */ 598c2ecf20Sopenharmony_ci "lsrl #5,%1\n\t" /* len/32 */ 608c2ecf20Sopenharmony_ci "jeq 2f\n\t" /* not enough... */ 618c2ecf20Sopenharmony_ci "subql #1,%1\n" 628c2ecf20Sopenharmony_ci "1:\t" 638c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 648c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 658c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 668c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 678c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 688c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 698c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 708c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 718c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 728c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 738c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 748c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 758c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 768c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 778c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 788c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 798c2ecf20Sopenharmony_ci "dbra %1,1b\n\t" 808c2ecf20Sopenharmony_ci "clrl %4\n\t" 818c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" /* add X bit */ 828c2ecf20Sopenharmony_ci "clrw %1\n\t" 838c2ecf20Sopenharmony_ci "subql #1,%1\n\t" 848c2ecf20Sopenharmony_ci "jcc 1b\n" 858c2ecf20Sopenharmony_ci "2:\t" 868c2ecf20Sopenharmony_ci "movel %3,%1\n\t" /* restore len from tmp1 */ 878c2ecf20Sopenharmony_ci "andw #0x1c,%3\n\t" /* number of rest longs */ 888c2ecf20Sopenharmony_ci "jeq 4f\n\t" 898c2ecf20Sopenharmony_ci "lsrw #2,%3\n\t" 908c2ecf20Sopenharmony_ci "subqw #1,%3\n" 918c2ecf20Sopenharmony_ci "3:\t" 928c2ecf20Sopenharmony_ci /* loop for rest longs */ 938c2ecf20Sopenharmony_ci "movel %2@+,%4\n\t" 948c2ecf20Sopenharmony_ci "addxl %4,%0\n\t" 958c2ecf20Sopenharmony_ci "dbra %3,3b\n\t" 968c2ecf20Sopenharmony_ci "clrl %4\n\t" 978c2ecf20Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 988c2ecf20Sopenharmony_ci "4:\t" 998c2ecf20Sopenharmony_ci /* now check for rest bytes that do not fit into longs */ 1008c2ecf20Sopenharmony_ci "andw #3,%1\n\t" 1018c2ecf20Sopenharmony_ci "jeq 7f\n\t" 1028c2ecf20Sopenharmony_ci "clrl %4\n\t" /* clear tmp2 for rest bytes */ 1038c2ecf20Sopenharmony_ci "subqw #2,%1\n\t" 1048c2ecf20Sopenharmony_ci "jlt 5f\n\t" 1058c2ecf20Sopenharmony_ci "movew %2@+,%4\n\t" /* have rest >= 2: get word */ 1068c2ecf20Sopenharmony_ci "swap %4\n\t" /* into bits 16..31 */ 1078c2ecf20Sopenharmony_ci "tstw %1\n\t" /* another byte? */ 1088c2ecf20Sopenharmony_ci "jeq 6f\n" 1098c2ecf20Sopenharmony_ci "5:\t" 1108c2ecf20Sopenharmony_ci "moveb %2@,%4\n\t" /* have odd rest: get byte */ 1118c2ecf20Sopenharmony_ci "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */ 1128c2ecf20Sopenharmony_ci "6:\t" 1138c2ecf20Sopenharmony_ci "addl %4,%0\n\t" /* now add rest long to sum */ 1148c2ecf20Sopenharmony_ci "clrl %4\n\t" 1158c2ecf20Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 1168c2ecf20Sopenharmony_ci "7:\t" 1178c2ecf20Sopenharmony_ci : "=d" (sum), "=d" (len), "=a" (buff), 1188c2ecf20Sopenharmony_ci "=&d" (tmp1), "=&d" (tmp2) 1198c2ecf20Sopenharmony_ci : "0" (sum), "1" (len), "2" (buff) 1208c2ecf20Sopenharmony_ci ); 1218c2ecf20Sopenharmony_ci return(sum); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_partial); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * copy from user space while checksumming, with exception handling. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci__wsum 1328c2ecf20Sopenharmony_cicsum_and_copy_from_user(const void __user *src, void *dst, int len) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * GCC doesn't like more than 10 operands for the asm 1368c2ecf20Sopenharmony_ci * statements so we have to use tmp2 for the error 1378c2ecf20Sopenharmony_ci * code. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci unsigned long tmp1, tmp2; 1408c2ecf20Sopenharmony_ci __wsum sum = ~0U; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci __asm__("movel %2,%4\n\t" 1438c2ecf20Sopenharmony_ci "btst #1,%4\n\t" /* Check alignment */ 1448c2ecf20Sopenharmony_ci "jeq 2f\n\t" 1458c2ecf20Sopenharmony_ci "subql #2,%1\n\t" /* buff%4==2: treat first word */ 1468c2ecf20Sopenharmony_ci "jgt 1f\n\t" 1478c2ecf20Sopenharmony_ci "addql #2,%1\n\t" /* len was == 2, treat only rest */ 1488c2ecf20Sopenharmony_ci "jra 4f\n" 1498c2ecf20Sopenharmony_ci "1:\n" 1508c2ecf20Sopenharmony_ci "10:\t" 1518c2ecf20Sopenharmony_ci "movesw %2@+,%4\n\t" /* add first word to sum */ 1528c2ecf20Sopenharmony_ci "addw %4,%0\n\t" 1538c2ecf20Sopenharmony_ci "movew %4,%3@+\n\t" 1548c2ecf20Sopenharmony_ci "clrl %4\n\t" 1558c2ecf20Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 1568c2ecf20Sopenharmony_ci "2:\t" 1578c2ecf20Sopenharmony_ci /* unrolled loop for the main part: do 8 longs at once */ 1588c2ecf20Sopenharmony_ci "movel %1,%4\n\t" /* save len in tmp1 */ 1598c2ecf20Sopenharmony_ci "lsrl #5,%1\n\t" /* len/32 */ 1608c2ecf20Sopenharmony_ci "jeq 2f\n\t" /* not enough... */ 1618c2ecf20Sopenharmony_ci "subql #1,%1\n" 1628c2ecf20Sopenharmony_ci "1:\n" 1638c2ecf20Sopenharmony_ci "11:\t" 1648c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1658c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1668c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1678c2ecf20Sopenharmony_ci "12:\t" 1688c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1698c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1708c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1718c2ecf20Sopenharmony_ci "13:\t" 1728c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1738c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1748c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1758c2ecf20Sopenharmony_ci "14:\t" 1768c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1778c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1788c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1798c2ecf20Sopenharmony_ci "15:\t" 1808c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1818c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1828c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1838c2ecf20Sopenharmony_ci "16:\t" 1848c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1858c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1868c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1878c2ecf20Sopenharmony_ci "17:\t" 1888c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1898c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1908c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1918c2ecf20Sopenharmony_ci "18:\t" 1928c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 1938c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 1948c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 1958c2ecf20Sopenharmony_ci "dbra %1,1b\n\t" 1968c2ecf20Sopenharmony_ci "clrl %5\n\t" 1978c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" /* add X bit */ 1988c2ecf20Sopenharmony_ci "clrw %1\n\t" 1998c2ecf20Sopenharmony_ci "subql #1,%1\n\t" 2008c2ecf20Sopenharmony_ci "jcc 1b\n" 2018c2ecf20Sopenharmony_ci "2:\t" 2028c2ecf20Sopenharmony_ci "movel %4,%1\n\t" /* restore len from tmp1 */ 2038c2ecf20Sopenharmony_ci "andw #0x1c,%4\n\t" /* number of rest longs */ 2048c2ecf20Sopenharmony_ci "jeq 4f\n\t" 2058c2ecf20Sopenharmony_ci "lsrw #2,%4\n\t" 2068c2ecf20Sopenharmony_ci "subqw #1,%4\n" 2078c2ecf20Sopenharmony_ci "3:\n" 2088c2ecf20Sopenharmony_ci /* loop for rest longs */ 2098c2ecf20Sopenharmony_ci "19:\t" 2108c2ecf20Sopenharmony_ci "movesl %2@+,%5\n\t" 2118c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 2128c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 2138c2ecf20Sopenharmony_ci "dbra %4,3b\n\t" 2148c2ecf20Sopenharmony_ci "clrl %5\n\t" 2158c2ecf20Sopenharmony_ci "addxl %5,%0\n" /* add X bit */ 2168c2ecf20Sopenharmony_ci "4:\t" 2178c2ecf20Sopenharmony_ci /* now check for rest bytes that do not fit into longs */ 2188c2ecf20Sopenharmony_ci "andw #3,%1\n\t" 2198c2ecf20Sopenharmony_ci "jeq 7f\n\t" 2208c2ecf20Sopenharmony_ci "clrl %5\n\t" /* clear tmp2 for rest bytes */ 2218c2ecf20Sopenharmony_ci "subqw #2,%1\n\t" 2228c2ecf20Sopenharmony_ci "jlt 5f\n\t" 2238c2ecf20Sopenharmony_ci "20:\t" 2248c2ecf20Sopenharmony_ci "movesw %2@+,%5\n\t" /* have rest >= 2: get word */ 2258c2ecf20Sopenharmony_ci "movew %5,%3@+\n\t" 2268c2ecf20Sopenharmony_ci "swap %5\n\t" /* into bits 16..31 */ 2278c2ecf20Sopenharmony_ci "tstw %1\n\t" /* another byte? */ 2288c2ecf20Sopenharmony_ci "jeq 6f\n" 2298c2ecf20Sopenharmony_ci "5:\n" 2308c2ecf20Sopenharmony_ci "21:\t" 2318c2ecf20Sopenharmony_ci "movesb %2@,%5\n\t" /* have odd rest: get byte */ 2328c2ecf20Sopenharmony_ci "moveb %5,%3@+\n\t" 2338c2ecf20Sopenharmony_ci "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */ 2348c2ecf20Sopenharmony_ci "6:\t" 2358c2ecf20Sopenharmony_ci "addl %5,%0\n\t" /* now add rest long to sum */ 2368c2ecf20Sopenharmony_ci "clrl %5\n\t" 2378c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" /* add X bit */ 2388c2ecf20Sopenharmony_ci "7:\t" 2398c2ecf20Sopenharmony_ci ".section .fixup,\"ax\"\n" 2408c2ecf20Sopenharmony_ci ".even\n" 2418c2ecf20Sopenharmony_ci /* If any exception occurs, return 0 */ 2428c2ecf20Sopenharmony_ci "90:\t" 2438c2ecf20Sopenharmony_ci "clrl %0\n" 2448c2ecf20Sopenharmony_ci "jra 7b\n" 2458c2ecf20Sopenharmony_ci ".previous\n" 2468c2ecf20Sopenharmony_ci ".section __ex_table,\"a\"\n" 2478c2ecf20Sopenharmony_ci ".long 10b,90b\n" 2488c2ecf20Sopenharmony_ci ".long 11b,90b\n" 2498c2ecf20Sopenharmony_ci ".long 12b,90b\n" 2508c2ecf20Sopenharmony_ci ".long 13b,90b\n" 2518c2ecf20Sopenharmony_ci ".long 14b,90b\n" 2528c2ecf20Sopenharmony_ci ".long 15b,90b\n" 2538c2ecf20Sopenharmony_ci ".long 16b,90b\n" 2548c2ecf20Sopenharmony_ci ".long 17b,90b\n" 2558c2ecf20Sopenharmony_ci ".long 18b,90b\n" 2568c2ecf20Sopenharmony_ci ".long 19b,90b\n" 2578c2ecf20Sopenharmony_ci ".long 20b,90b\n" 2588c2ecf20Sopenharmony_ci ".long 21b,90b\n" 2598c2ecf20Sopenharmony_ci ".previous" 2608c2ecf20Sopenharmony_ci : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), 2618c2ecf20Sopenharmony_ci "=&d" (tmp1), "=d" (tmp2) 2628c2ecf20Sopenharmony_ci : "0" (sum), "1" (len), "2" (src), "3" (dst) 2638c2ecf20Sopenharmony_ci ); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return sum; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_and_copy_from_user); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* 2728c2ecf20Sopenharmony_ci * copy from kernel space while checksumming, otherwise like csum_partial 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci__wsum 2768c2ecf20Sopenharmony_cicsum_partial_copy_nocheck(const void *src, void *dst, int len) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci unsigned long tmp1, tmp2; 2798c2ecf20Sopenharmony_ci __wsum sum = 0; 2808c2ecf20Sopenharmony_ci __asm__("movel %2,%4\n\t" 2818c2ecf20Sopenharmony_ci "btst #1,%4\n\t" /* Check alignment */ 2828c2ecf20Sopenharmony_ci "jeq 2f\n\t" 2838c2ecf20Sopenharmony_ci "subql #2,%1\n\t" /* buff%4==2: treat first word */ 2848c2ecf20Sopenharmony_ci "jgt 1f\n\t" 2858c2ecf20Sopenharmony_ci "addql #2,%1\n\t" /* len was == 2, treat only rest */ 2868c2ecf20Sopenharmony_ci "jra 4f\n" 2878c2ecf20Sopenharmony_ci "1:\t" 2888c2ecf20Sopenharmony_ci "movew %2@+,%4\n\t" /* add first word to sum */ 2898c2ecf20Sopenharmony_ci "addw %4,%0\n\t" 2908c2ecf20Sopenharmony_ci "movew %4,%3@+\n\t" 2918c2ecf20Sopenharmony_ci "clrl %4\n\t" 2928c2ecf20Sopenharmony_ci "addxl %4,%0\n" /* add X bit */ 2938c2ecf20Sopenharmony_ci "2:\t" 2948c2ecf20Sopenharmony_ci /* unrolled loop for the main part: do 8 longs at once */ 2958c2ecf20Sopenharmony_ci "movel %1,%4\n\t" /* save len in tmp1 */ 2968c2ecf20Sopenharmony_ci "lsrl #5,%1\n\t" /* len/32 */ 2978c2ecf20Sopenharmony_ci "jeq 2f\n\t" /* not enough... */ 2988c2ecf20Sopenharmony_ci "subql #1,%1\n" 2998c2ecf20Sopenharmony_ci "1:\t" 3008c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3018c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3028c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3038c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3048c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3058c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3068c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3078c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3088c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3098c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3108c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3118c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3128c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3138c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3148c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3158c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3168c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3178c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3188c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3198c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3208c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3218c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3228c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3238c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3248c2ecf20Sopenharmony_ci "dbra %1,1b\n\t" 3258c2ecf20Sopenharmony_ci "clrl %5\n\t" 3268c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" /* add X bit */ 3278c2ecf20Sopenharmony_ci "clrw %1\n\t" 3288c2ecf20Sopenharmony_ci "subql #1,%1\n\t" 3298c2ecf20Sopenharmony_ci "jcc 1b\n" 3308c2ecf20Sopenharmony_ci "2:\t" 3318c2ecf20Sopenharmony_ci "movel %4,%1\n\t" /* restore len from tmp1 */ 3328c2ecf20Sopenharmony_ci "andw #0x1c,%4\n\t" /* number of rest longs */ 3338c2ecf20Sopenharmony_ci "jeq 4f\n\t" 3348c2ecf20Sopenharmony_ci "lsrw #2,%4\n\t" 3358c2ecf20Sopenharmony_ci "subqw #1,%4\n" 3368c2ecf20Sopenharmony_ci "3:\t" 3378c2ecf20Sopenharmony_ci /* loop for rest longs */ 3388c2ecf20Sopenharmony_ci "movel %2@+,%5\n\t" 3398c2ecf20Sopenharmony_ci "addxl %5,%0\n\t" 3408c2ecf20Sopenharmony_ci "movel %5,%3@+\n\t" 3418c2ecf20Sopenharmony_ci "dbra %4,3b\n\t" 3428c2ecf20Sopenharmony_ci "clrl %5\n\t" 3438c2ecf20Sopenharmony_ci "addxl %5,%0\n" /* add X bit */ 3448c2ecf20Sopenharmony_ci "4:\t" 3458c2ecf20Sopenharmony_ci /* now check for rest bytes that do not fit into longs */ 3468c2ecf20Sopenharmony_ci "andw #3,%1\n\t" 3478c2ecf20Sopenharmony_ci "jeq 7f\n\t" 3488c2ecf20Sopenharmony_ci "clrl %5\n\t" /* clear tmp2 for rest bytes */ 3498c2ecf20Sopenharmony_ci "subqw #2,%1\n\t" 3508c2ecf20Sopenharmony_ci "jlt 5f\n\t" 3518c2ecf20Sopenharmony_ci "movew %2@+,%5\n\t" /* have rest >= 2: get word */ 3528c2ecf20Sopenharmony_ci "movew %5,%3@+\n\t" 3538c2ecf20Sopenharmony_ci "swap %5\n\t" /* into bits 16..31 */ 3548c2ecf20Sopenharmony_ci "tstw %1\n\t" /* another byte? */ 3558c2ecf20Sopenharmony_ci "jeq 6f\n" 3568c2ecf20Sopenharmony_ci "5:\t" 3578c2ecf20Sopenharmony_ci "moveb %2@,%5\n\t" /* have odd rest: get byte */ 3588c2ecf20Sopenharmony_ci "moveb %5,%3@+\n\t" 3598c2ecf20Sopenharmony_ci "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ 3608c2ecf20Sopenharmony_ci "6:\t" 3618c2ecf20Sopenharmony_ci "addl %5,%0\n\t" /* now add rest long to sum */ 3628c2ecf20Sopenharmony_ci "clrl %5\n\t" 3638c2ecf20Sopenharmony_ci "addxl %5,%0\n" /* add X bit */ 3648c2ecf20Sopenharmony_ci "7:\t" 3658c2ecf20Sopenharmony_ci : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), 3668c2ecf20Sopenharmony_ci "=&d" (tmp1), "=&d" (tmp2) 3678c2ecf20Sopenharmony_ci : "0" (sum), "1" (len), "2" (src), "3" (dst) 3688c2ecf20Sopenharmony_ci ); 3698c2ecf20Sopenharmony_ci return(sum); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(csum_partial_copy_nocheck); 372