/* SPDX-License-Identifier: GPL-2.0+1*2* $Id: checksum.S,v 1.10 2001/07/06 13:11:32 gniibe Exp $3*4* INET An implementation of the TCP/IP protocol suite for the LINUX5* operating system. INET is implemented using the BSD Socket6* interface as the means of communication with the user level.7*8* IP/TCP/UDP checksumming routines9*10* Authors: Jorge Cwik, <[email protected]>11* Arnt Gulbrandsen, <[email protected]>12* Tom May, <[email protected]>13* Pentium Pro/II routines:14* Alexander Kjeldaas <[email protected]>15* Finn Arne Gangstad <[email protected]>16* Lots of code moved from tcp.c and ip.c; see those files17* for more names.18*19* Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception20* handling.21* Andi Kleen, add zeroing on error22* converted to pure assembler23*24* SuperH version: Copyright (C) 1999 Niibe Yutaka25*/2627#include <asm/errno.h>28#include <linux/linkage.h>2930/*31* computes a partial checksum, e.g. for TCP/UDP fragments32*/3334/*35* unsigned int csum_partial(const unsigned char *buf, int len,36* unsigned int sum);37*/3839.text40ENTRY(csum_partial)41/*42* Experiments with Ethernet and SLIP connections show that buff43* is aligned on either a 2-byte or 4-byte boundary. We get at44* least a twofold speedup on 486 and Pentium if it is 4-byte aligned.45* Fortunately, it is easy to convert 2-byte alignment to 4-byte46* alignment for the unrolled loop.47*/48mov r5, r149mov r4, r050tst #2, r0 ! Check alignment.51bt 2f ! Jump if alignment is ok.52!53add #-2, r5 ! Alignment uses up two bytes.54cmp/pz r5 !55bt/s 1f ! Jump if we had at least two bytes.56clrt57bra 6f58add #2, r5 ! r5 was < 2. Deal with it.591:60mov r5, r1 ! Save new len for later use.61mov.w @r4+, r062extu.w r0, r063addc r0, r664bf 2f65add #1, r6662:67mov #-5, r068shld r0, r569tst r5, r570bt/s 4f ! if it's =0, go to 4f71clrt72.align 2733:74mov.l @r4+, r075mov.l @r4+, r276mov.l @r4+, r377addc r0, r678mov.l @r4+, r079addc r2, r680mov.l @r4+, r281addc r3, r682mov.l @r4+, r383addc r0, r684mov.l @r4+, r085addc r2, r686mov.l @r4+, r287addc r3, r688addc r0, r689addc r2, r690movt r091dt r592bf/s 3b93cmp/eq #1, r094! here, we know r5==095addc r5, r6 ! add carry to r6964:97mov r1, r098and #0x1c, r099tst r0, r0100bt/s 6f101mov r0, r5102shlr2 r5103mov #0, r21045:105addc r2, r6106mov.l @r4+, r2107movt r0108dt r5109bf/s 5b110cmp/eq #1, r0111addc r2, r6112addc r5, r6 ! r5==0 here, so it means add carry-bit1136:114mov r1, r5115mov #3, r0116and r0, r5117tst r5, r5118bt 9f ! if it's =0 go to 9f119mov #2, r1120cmp/hs r1, r5121bf 7f122mov.w @r4+, r0123extu.w r0, r0124cmp/eq r1, r5125bt/s 8f126clrt127shll16 r0128addc r0, r61297:130mov.b @r4+, r0131extu.b r0, r0132#ifndef __LITTLE_ENDIAN__133shll8 r0134#endif1358:136addc r0, r6137mov #0, r0138addc r0, r61399:140rts141mov r6, r0142143/*144unsigned int csum_partial_copy_generic (const char *src, char *dst, int len)145*/146147/*148* Copy from ds while checksumming, otherwise like csum_partial with initial149* sum being ~0U150*/151152#define EXC(...) \1539999: __VA_ARGS__ ; \154.section __ex_table, "a"; \155.long 9999b, 6001f ; \156.previous157158!159! r4: const char *SRC160! r5: char *DST161! r6: int LEN162!163ENTRY(csum_partial_copy_generic)164mov #-1,r7165mov #3,r0 ! Check src and dest are equally aligned166mov r4,r1167and r0,r1168and r5,r0169cmp/eq r1,r0170bf 3f ! Different alignments, use slow version171tst #1,r0 ! Check dest word aligned172bf 3f ! If not, do it the slow way173174mov #2,r0175tst r0,r5 ! Check dest alignment.176bt 2f ! Jump if alignment is ok.177add #-2,r6 ! Alignment uses up two bytes.178cmp/pz r6 ! Jump if we had at least two bytes.179bt/s 1f180clrt181add #2,r6 ! r6 was < 2. Deal with it.182bra 4f183mov r6,r21841853: ! Handle different src and dest alignments.186! This is not common, so simple byte by byte copy will do.187mov r6,r2188shlr r6189tst r6,r6190bt 4f191clrt192.align 21935:194EXC( mov.b @r4+,r1 )195EXC( mov.b @r4+,r0 )196extu.b r1,r1197EXC( mov.b r1,@r5 )198EXC( mov.b r0,@(1,r5) )199extu.b r0,r0200add #2,r5201202#ifdef __LITTLE_ENDIAN__203shll8 r0204#else205shll8 r1206#endif207or r1,r0208209addc r0,r7210movt r0211dt r6212bf/s 5b213cmp/eq #1,r0214mov #0,r0215addc r0, r7216217mov r2, r0218tst #1, r0219bt 7f220bra 5f221clrt222223! src and dest equally aligned, but to a two byte boundary.224! Handle first two bytes as a special case225.align 22261:227EXC( mov.w @r4+,r0 )228EXC( mov.w r0,@r5 )229add #2,r5230extu.w r0,r0231addc r0,r7232mov #0,r0233addc r0,r72342:235mov r6,r2236mov #-5,r0237shld r0,r6238tst r6,r6239bt/s 2f240clrt241.align 22421:243EXC( mov.l @r4+,r0 )244EXC( mov.l @r4+,r1 )245addc r0,r7246EXC( mov.l r0,@r5 )247EXC( mov.l r1,@(4,r5) )248addc r1,r7249250EXC( mov.l @r4+,r0 )251EXC( mov.l @r4+,r1 )252addc r0,r7253EXC( mov.l r0,@(8,r5) )254EXC( mov.l r1,@(12,r5) )255addc r1,r7256257EXC( mov.l @r4+,r0 )258EXC( mov.l @r4+,r1 )259addc r0,r7260EXC( mov.l r0,@(16,r5) )261EXC( mov.l r1,@(20,r5) )262addc r1,r7263264EXC( mov.l @r4+,r0 )265EXC( mov.l @r4+,r1 )266addc r0,r7267EXC( mov.l r0,@(24,r5) )268EXC( mov.l r1,@(28,r5) )269addc r1,r7270add #32,r5271movt r0272dt r6273bf/s 1b274cmp/eq #1,r0275mov #0,r0276addc r0,r72772782: mov r2,r6279mov #0x1c,r0280and r0,r6281cmp/pl r6282bf/s 4f283clrt284shlr2 r62853:286EXC( mov.l @r4+,r0 )287addc r0,r7288EXC( mov.l r0,@r5 )289add #4,r5290movt r0291dt r6292bf/s 3b293cmp/eq #1,r0294mov #0,r0295addc r0,r72964: mov r2,r6297mov #3,r0298and r0,r6299cmp/pl r6300bf 7f301mov #2,r1302cmp/hs r1,r6303bf 5f304EXC( mov.w @r4+,r0 )305EXC( mov.w r0,@r5 )306extu.w r0,r0307add #2,r5308cmp/eq r1,r6309bt/s 6f310clrt311shll16 r0312addc r0,r73135:314EXC( mov.b @r4+,r0 )315EXC( mov.b r0,@r5 )316extu.b r0,r0317#ifndef __LITTLE_ENDIAN__318shll8 r0319#endif3206: addc r0,r7321mov #0,r0322addc r0,r73237:324325# Exception handler:326.section .fixup, "ax"3273286001:329rts330mov #0,r0331.previous332rts333mov r7,r0334335336