1*45162Ssklower#define M_OFF	4
2*45162Ssklower#define M_LEN	8
3*45162Ssklower#define IPHLEN 20			/* sizeof(struct ip) */
4*45162Ssklower#define	LGP	2			/* log2(adds in unrolled loop) */
5*45162Ssklower#define ADDLEN	24
6*45162Ssklower
7*45162Ssklower # r0	checksum result				result
8*45162Ssklower # r1	current longword to add			curlong
9*45162Ssklower # r2	pointer to data				p
10*45162Ssklower # r3	byte count in current mbuf		count
11*45162Ssklower # r4	"odd" byte count			bytenum
12*45162Ssklower # r5	pointer to mbuf chain			m
13*45162Ssklower
14*45162Ssklower.text
15*45162Ssklower.align 1
16*45162Ssklower.globl	_rdp_cksum
17*45162Ssklower
18*45162Ssklower_rdp_cksum:
19*45162Ssklower.set MASK, 0x00c0
20*45162Ssklower	.word MASK			# use r6,r7 (in addition to r0-r5)
21*45162Ssklower
22*45162Ssklower	movl	4(ap), r5		# m = arg to function
23*45162Ssklower	clrl	r0			# result = 0
24*45162Ssklower
25*45162Ssklower	# Assume IP header and RDP header always with in first mbuf.
26*45162Ssklower	# Assume mbuf chain is at least 1 long
27*45162Ssklower
28*45162Ssklower	addl3	M_OFF (r5), r5, r2	# p = mtod(m, cast)
29*45162Ssklower	addl2	$IPHLEN, r2		# p += sizeof(struct ip)
30*45162Ssklower	subw3	$IPHLEN, M_LEN (r5), r3 # count = m->m_len - sizeof(struct ip)
31*45162Ssklower	cvtwl	r3, r3
32*45162Ssklower
33*45162SsklowerLdombuf:
34*45162Ssklower	# Determine the number of longwords in this mbuf.  Note that we
35*45162Ssklower	# are depending on the VAX Architecture that allows access to
36*45162Ssklower	# non-aligned data.  (When we cross MBUF boundries an an earlier
37*45162Ssklower	# one was not filled with an 'even' number of bytes for longwords).
38*45162Ssklower
39*45162Ssklower	ashl	$-2, r3, r6		# n_longs = n_bytes >> 2
40*45162Ssklower	extzv	$0, $2, r3, r4		# bytenum = n_bytes & 3
41*45162Ssklower
42*45162Ssklower	# Now, can add together as many longwords as possible.  We have
43*45162Ssklower	# unrolled the loop for efficiency, so let's calculate the number
44*45162Ssklower	# of times through the loop and the partial pass.
45*45162Ssklower
46*45162Ssklower	extzv	$0, $LGP, r6, r7	# r7 = # adds in partial pass
47*45162Ssklower	ashl	$-LGP, r6, r6		# r6 = # whole passes
48*45162Ssklower
49*45162Ssklower	mull2	$ADDLEN, r7		# convert adds to bytes of instruc
50*45162Ssklower	subl3	r7, $Lhere, r7
51*45162Ssklower	jmp	(r7)			# and jump into the loop
52*45162Ssklower
53*45162Ssklower	#
54*45162Ssklower	# There is VAX order, adding order, and network order to consider
55*45162Ssklower	#
56*45162Ssklower	# VAX order: 80 1 2 3 is the VAX integer 03020180 since the low
57*45162Ssklower	#	bytes come first when treated as an unsigned character array
58*45162Ssklower	#	on the vax.
59*45162Ssklower	#
60*45162Ssklower	# adding order: add so that carries propogate in the same manner that
61*45162Ssklower	#	they would if the machine had its bytes in network order
62*45162Ssklower	#	    80 01 02 03 + 80 01 02 03 = 00020406, since 80 is msb
63*45162Ssklower	#	    00 80 00 00 + 00 80 00 00 = 01000000
64*45162Ssklower	#	This is just essentially getting the bytes into the host's
65*45162Ssklower	#	integer format.  adding order should work for the rotate too.
66*45162Ssklower	#	We MUST add the bytes in adding order so that different
67*45162Ssklower	#	machine architectures get the same result.  We cannot add
68*45162Ssklower	#	in native mode and f(result) because the propogation of
69*45162Ssklower	#	carries in native cannot be made equivalent to the propogation
70*45162Ssklower	#	of carries in adding order
71*45162Ssklower	#
72*45162Ssklower	# network order: The resulting checksum should be transferred in
73*45162Ssklower	#	network order.  The VAX result 01020304 would be converted
74*45162Ssklower	#	to 04030201 for communication with remote host.
75*45162Ssklower	#
76*45162Ssklower
77*45162SsklowerLtop:
78*45162Ssklower#define SUML \
79*45162Ssklower	;movl	(r2)+, r7		/* fetch longword */		\
80*45162Ssklower	;rotl	$-8, r7, r1		/* put it in adding order */	\
81*45162Ssklower	;insv	r1, $16, $8, r1						\
82*45162Ssklower	;movb	-1(r2), r1						\
83*45162Ssklower	;addl2	r1, r0			/* result += ... */		\
84*45162Ssklower	;rotl	$1, r0, r0		/* and rotate it per spec */
85*45162Ssklower
86*45162Ssklower	SUML
87*45162Ssklower	SUML
88*45162Ssklower	SUML
89*45162Ssklower	SUML
90*45162SsklowerLhere:
91*45162Ssklower	sobgeq	r6, Ltop
92*45162Ssklower
93*45162Ssklower	# Now, add in remaining bytes, if any
94*45162Ssklower
95*45162Ssklower	tstl	r4
96*45162Ssklower	bneq	Leftovers
97*45162Ssklower	movl	(r5), r5		# m = m->m_next
98*45162Ssklower	bneq	Lnextmbuf
99*45162SsklowerLdone:
100*45162Ssklower	# Convert result from adding order to network order
101*45162Ssklower
102*45162Ssklower	pushl	r0
103*45162Ssklower	rotl	$-8,(sp),r0
104*45162Ssklower	insv	r0,$16,$8,r0
105*45162Ssklower	movb	3(sp),r0
106*45162Ssklower	addl2	$4, sp
107*45162Ssklower
108*45162Ssklower	ret
109*45162Ssklower
110*45162SsklowerLnextmbuf:
111*45162Ssklower	addl3	M_OFF (r5), r5, r2	# p = mtod(m, cast)
112*45162Ssklower	cvtwl	M_LEN (r5), r3		# count = m->m_len
113*45162Ssklower	brw	Ldombuf			# assume zero length mbufs unusual
114*45162Ssklower
115*45162Ssklower	# In adding in the remainder of this mbuf and part of the next one,
116*45162Ssklower	# we're trying to build up a single 32 bit quantity for adding into
117*45162Ssklower	# the checksum.
118*45162Ssklower	#
119*45162Ssklower	# use fact that:
120*45162Ssklower	#	result += curlong = (a<<24) | (b<<16) | (c<<8) | d
121*45162Ssklower	# is the same as
122*45162Ssklower	#	result += a<<24; result += b<<16; result += c<<8; result += d
123*45162Ssklower
124*45162SsklowerLeftovers:
125*45162Ssklower	movl	$3, r6
126*45162SsklowerL1:
127*45162Ssklower	movzbl	(r2)+, r1		# r1 = this byte (unsigned char)
128*45162Ssklower	ashl	$3, r6, r7		# r7 = r6 * 8
129*45162Ssklower	ashl	r7, r1, r1		# r1 <<= r7
130*45162Ssklower	addl2	r1, r0			# result += this byte
131*45162Ssklower	decl	r6
132*45162Ssklower	sobgtr	r4, L1			# get next byte in this mbuf
133*45162Ssklower
134*45162Ssklower	# Now, grab bytes from next mbuf
135*45162SsklowerL2:
136*45162Ssklower	movl	(r5), r5
137*45162Ssklower	bneq	L3
138*45162Ssklower	rotl	$1, r0, r0		# last mbuf had odd byte count
139*45162Ssklower	brw	Ldone
140*45162SsklowerL3:
141*45162Ssklower	cvtwl	M_LEN (r5), r3		# count = m->m_len
142*45162Ssklower	beql	L2			# if (count == 0) do next mbuf
143*45162Ssklower	addl3	M_OFF (r5), r5, r2	# p = mtod(m, cast)
144*45162SsklowerL4:
145*45162Ssklower	movzbl	(r2)+, r1		# r1 = this byte (unsigned char)
146*45162Ssklower	ashl	$3, r6, r7		# r7 = r6 * 8
147*45162Ssklower	ashl	r7, r1, r1		# r1 <<= r7
148*45162Ssklower	addl2	r1, r0			# result += this byte
149*45162Ssklower	decl	r6
150*45162Ssklower	bgeq	L5			# got last byte in long?
151*45162Ssklower	rotl	$1, r0, r0
152*45162Ssklower	decl	r3
153*45162Ssklower	brw	Ldombuf			# and continue checksumming
154*45162SsklowerL5:
155*45162Ssklower	sobgtr	r3, L4			# grab next byte from this mbuf
156*45162Ssklower	brb	L2			# but go to next if have too
157