cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

checksum.c (2543B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * INET		An implementation of the TCP/IP protocol suite for the LINUX
      4 *		operating system.  INET is implemented using the  BSD Socket
      5 *		interface as the means of communication with the user level.
      6 *
      7 *		MIPS specific IP/TCP/UDP checksumming routines
      8 *
      9 * Authors:	Ralf Baechle, <ralf@waldorf-gmbh.de>
     10 *		Lots of code moved from tcp.c and ip.c; see those files
     11 *		for more names.
     12 */
     13#include <linux/module.h>
     14#include <linux/types.h>
     15
     16#include <net/checksum.h>
     17#include <asm/byteorder.h>
     18#include <asm/string.h>
     19#include <linux/uaccess.h>
     20
     21#define addc(_t,_r)                     \
     22	__asm__ __volatile__ (          \
     23"       add             %0, %1, %0\n"   \
     24"       addc            %0, %%r0, %0\n" \
     25	: "=r"(_t)                      \
     26	: "r"(_r), "0"(_t));
     27
     28static inline unsigned short from32to16(unsigned int x)
     29{
     30	/* 32 bits --> 16 bits + carry */
     31	x = (x & 0xffff) + (x >> 16);
     32	/* 16 bits + carry --> 16 bits including carry */
     33	x = (x & 0xffff) + (x >> 16);
     34	return (unsigned short)x;
     35}
     36
     37static inline unsigned int do_csum(const unsigned char * buff, int len)
     38{
     39	int odd, count;
     40	unsigned int result = 0;
     41
     42	if (len <= 0)
     43		goto out;
     44	odd = 1 & (unsigned long) buff;
     45	if (odd) {
     46		result = be16_to_cpu(*buff);
     47		len--;
     48		buff++;
     49	}
     50	count = len >> 1;		/* nr of 16-bit words.. */
     51	if (count) {
     52		if (2 & (unsigned long) buff) {
     53			result += *(unsigned short *) buff;
     54			count--;
     55			len -= 2;
     56			buff += 2;
     57		}
     58		count >>= 1;		/* nr of 32-bit words.. */
     59		if (count) {
     60			while (count >= 4) {
     61				unsigned int r1, r2, r3, r4;
     62				r1 = *(unsigned int *)(buff + 0);
     63				r2 = *(unsigned int *)(buff + 4);
     64				r3 = *(unsigned int *)(buff + 8);
     65				r4 = *(unsigned int *)(buff + 12);
     66				addc(result, r1);
     67				addc(result, r2);
     68				addc(result, r3);
     69				addc(result, r4);
     70				count -= 4;
     71				buff += 16;
     72			}
     73			while (count) {
     74				unsigned int w = *(unsigned int *) buff;
     75				count--;
     76				buff += 4;
     77				addc(result, w);
     78			}
     79			result = (result & 0xffff) + (result >> 16);
     80		}
     81		if (len & 2) {
     82			result += *(unsigned short *) buff;
     83			buff += 2;
     84		}
     85	}
     86	if (len & 1)
     87		result += le16_to_cpu(*buff);
     88	result = from32to16(result);
     89	if (odd)
     90		result = swab16(result);
     91out:
     92	return result;
     93}
     94
     95/*
     96 * computes a partial checksum, e.g. for TCP/UDP fragments
     97 */
     98/*
     99 * why bother folding?
    100 */
    101__wsum csum_partial(const void *buff, int len, __wsum sum)
    102{
    103	unsigned int result = do_csum(buff, len);
    104	addc(result, sum);
    105	return (__force __wsum)from32to16(result);
    106}
    107
    108EXPORT_SYMBOL(csum_partial);