blob: 407beebadaf45a748f91a36b78bd1d023449b132 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
H. Peter Anvin1965aae2008-10-22 22:26:29 -07002#ifndef _ASM_X86_CHECKSUM_64_H
3#define _ASM_X86_CHECKSUM_64_H
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
Joe Perches3d3c6e12008-03-23 01:01:50 -07005/*
6 * Checksums for x86-64
7 * Copyright 2002 by Andi Kleen, SuSE Labs
Dave Jones99122a32008-01-30 13:30:28 +01008 * with some code from asm-x86/checksum.h
Joe Perches3d3c6e12008-03-23 01:01:50 -07009 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070010
11#include <linux/compiler.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080012#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/byteorder.h>
14
Joe Perches3d3c6e12008-03-23 01:01:50 -070015/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 * csum_fold - Fold and invert a 32bit checksum.
17 * sum: 32bit unfolded sum
Joe Perches3d3c6e12008-03-23 01:01:50 -070018 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 * Fold a 32bit running checksum to 16bit and invert it. This is usually
20 * the last step before putting a checksum into a packet.
21 * Make sure not to mix with 64bit checksums.
22 */
Al Viroa4f89fb2006-11-14 21:20:08 -080023static inline __sum16 csum_fold(__wsum sum)
Linus Torvalds1da177e2005-04-16 15:20:36 -070024{
Joe Perches3d3c6e12008-03-23 01:01:50 -070025 asm(" addl %1,%0\n"
26 " adcl $0xffff,%0"
27 : "=r" (sum)
28 : "r" ((__force u32)sum << 16),
29 "0" ((__force u32)sum & 0xffff0000));
Al Viroa4f89fb2006-11-14 21:20:08 -080030 return (__force __sum16)(~(__force u32)sum >> 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031}
32
33/*
34 * This is a version of ip_compute_csum() optimized for IP headers,
35 * which always checksum on 4 octet boundaries.
36 *
37 * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
38 * Arnt Gulbrandsen.
39 */
40
41/**
42 * ip_fast_csum - Compute the IPv4 header checksum efficiently.
43 * iph: ipv4 header
44 * ihl: length of header / 4
Joe Perches3d3c6e12008-03-23 01:01:50 -070045 */
Al Viroa4f89fb2006-11-14 21:20:08 -080046static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
Linus Torvalds1da177e2005-04-16 15:20:36 -070047{
48 unsigned int sum;
49
Joe Perches3d3c6e12008-03-23 01:01:50 -070050 asm(" movl (%1), %0\n"
51 " subl $4, %2\n"
52 " jbe 2f\n"
53 " addl 4(%1), %0\n"
54 " adcl 8(%1), %0\n"
55 " adcl 12(%1), %0\n"
56 "1: adcl 16(%1), %0\n"
57 " lea 4(%1), %1\n"
58 " decl %2\n"
59 " jne 1b\n"
60 " adcl $0, %0\n"
61 " movl %0, %2\n"
62 " shrl $16, %0\n"
63 " addw %w2, %w0\n"
64 " adcl $0, %0\n"
65 " notl %0\n"
66 "2:"
Thomas Graf2c656492005-08-20 17:24:25 -070067 /* Since the input registers which are loaded with iph and ihl
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 are modified, we must also specify them as outputs, or gcc
69 will assume they contain their original values. */
Joe Perches3d3c6e12008-03-23 01:01:50 -070070 : "=r" (sum), "=r" (iph), "=r" (ihl)
71 : "1" (iph), "2" (ihl)
72 : "memory");
Al Viroa4f89fb2006-11-14 21:20:08 -080073 return (__force __sum16)sum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074}
75
Joe Perches3d3c6e12008-03-23 01:01:50 -070076/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
78 * @saddr: source address
79 * @daddr: destination address
80 * @len: length of packet
81 * @proto: ip protocol of packet
Joe Perches3d3c6e12008-03-23 01:01:50 -070082 * @sum: initial sum to be added in (32bit unfolded)
83 *
84 * Returns the pseudo header checksum the input data. Result is
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 * 32bit unfolded.
86 */
Al Viroa4f89fb2006-11-14 21:20:08 -080087static inline __wsum
Alexander Duyck01cfbad2016-03-11 14:05:34 -080088csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
89 __u8 proto, __wsum sum)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
91 asm(" addl %1, %0\n"
92 " adcl %2, %0\n"
93 " adcl %3, %0\n"
94 " adcl $0, %0\n"
Joe Perches3d3c6e12008-03-23 01:01:50 -070095 : "=r" (sum)
Al Viroa4f89fb2006-11-14 21:20:08 -080096 : "g" (daddr), "g" (saddr),
97 "g" ((len + proto)<<8), "0" (sum));
Joe Perches3d3c6e12008-03-23 01:01:50 -070098 return sum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099}
100
101
Joe Perches3d3c6e12008-03-23 01:01:50 -0700102/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 * csum_tcpup_magic - Compute an IPv4 pseudo header checksum.
104 * @saddr: source address
105 * @daddr: destination address
106 * @len: length of packet
107 * @proto: ip protocol of packet
Joe Perches3d3c6e12008-03-23 01:01:50 -0700108 * @sum: initial sum to be added in (32bit unfolded)
109 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 * Returns the 16bit pseudo header checksum the input data already
111 * complemented and ready to be filled in.
112 */
Joe Perches3d3c6e12008-03-23 01:01:50 -0700113static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
Alexander Duyck01cfbad2016-03-11 14:05:34 -0800114 __u32 len, __u8 proto,
115 __wsum sum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Joe Perches3d3c6e12008-03-23 01:01:50 -0700117 return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118}
119
Joe Perches3d3c6e12008-03-23 01:01:50 -0700120/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 * csum_partial - Compute an internet checksum.
122 * @buff: buffer to be checksummed
123 * @len: length of buffer.
124 * @sum: initial sum to be added in (32bit unfolded)
125 *
126 * Returns the 32bit unfolded internet checksum of the buffer.
127 * Before filling it in it needs to be csum_fold()'ed.
128 * buff should be aligned to a 64bit boundary if possible.
Joe Perches3d3c6e12008-03-23 01:01:50 -0700129 */
Al Viroa4f89fb2006-11-14 21:20:08 -0800130extern __wsum csum_partial(const void *buff, int len, __wsum sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/* Do not call this directly. Use the wrappers below */
Al Virodaf52372020-07-19 21:56:07 -0400133extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Al Viroc693cc42020-07-11 00:27:49 -0400135extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
136extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
Al Virocc44c172020-07-11 00:12:07 -0400137extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Joe Perches3d3c6e12008-03-23 01:01:50 -0700139/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 * ip_compute_csum - Compute an 16bit IP checksum.
141 * @buff: buffer address.
142 * @len: length of buffer.
143 *
144 * Returns the 16bit folded/inverted checksum of the passed buffer.
145 * Ready to fill in.
146 */
Al Viroa4f89fb2006-11-14 21:20:08 -0800147extern __sum16 ip_compute_csum(const void *buff, int len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149/**
150 * csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.
151 * @saddr: source address
152 * @daddr: destination address
153 * @len: length of packet
154 * @proto: protocol of packet
155 * @sum: initial sum (32bit unfolded) to be added in
156 *
Joe Perches3d3c6e12008-03-23 01:01:50 -0700157 * Computes an IPv6 pseudo header checksum. This sum is added the checksum
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 * into UDP/TCP packets and contains some link layer information.
159 * Returns the unfolded 32bit checksum.
160 */
161
162struct in6_addr;
163
164#define _HAVE_ARCH_IPV6_CSUM 1
Al Viroa4f89fb2006-11-14 21:20:08 -0800165extern __sum16
166csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
Alexander Duyck1e940822016-03-11 14:05:41 -0800167 __u32 len, __u8 proto, __wsum sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169static inline unsigned add32_with_carry(unsigned a, unsigned b)
170{
171 asm("addl %2,%0\n\t"
Joe Perches3d3c6e12008-03-23 01:01:50 -0700172 "adcl $0,%0"
173 : "=r" (a)
Tom Herbert4405b4d2014-05-02 16:28:40 -0700174 : "0" (a), "rm" (b));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 return a;
176}
177
Tom Herberta2785342014-05-02 16:28:15 -0700178#define HAVE_ARCH_CSUM_ADD
179static inline __wsum csum_add(__wsum csum, __wsum addend)
180{
181 return (__force __wsum)add32_with_carry((__force unsigned)csum,
182 (__force unsigned)addend);
183}
184
H. Peter Anvin1965aae2008-10-22 22:26:29 -0700185#endif /* _ASM_X86_CHECKSUM_64_H */