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