#include <machine/asm.h>
__KERNEL_RCSID(0, "$NetBSD: cpu_in_cksum.S,v 1.1 2018/04/25 11:06:49 ragge Exp $");
#include "assym.h"
#define off %r0
#define mlen %r1
#define m %r2
#define data %r3
#define sum %r4
#define len %r5
#define byte_swapped %r6
#define tmp %r7
#
#
ENTRY(cpu_in_cksum, R7|R6)
subl2 $4,%sp
movl 4(%ap),m
movl 8(%ap),len
movl 12(%ap),off
movl 16(%ap),sum
clrl byte_swapped
.Lfirstloop: # for (;;) {
tstl m # if (__predict_false(m == NULL)) {
jeql .Lout_of_data
movl M_LEN(m),mlen # mlen = m->m_len;
cmpl off,mlen # if (mlen > off) {
jgeq 1f
subl2 off,mlen # mlen -= off;
addl3 M_DATA(m),off,data # data = mtod(m, uint8_t *) + off;
jbr .Lpost_initial_offset # goto post_initial_offset;
1: # }
subl2 mlen,off # off -= mlen;
tstl len # if (len == 0)
jeql .Lsecondloop # break;
movl M_NEXT(m),m # m = m->m_next;
jbr .Lfirstloop # }
.Lthirdstmt:
movl M_NEXT(m),m # m = m->m_next) {
.Lsecondloop: # for (;
tstl len # len > 0;
jeql .Lendsecond
tstl m # if (__predict_false(m == NULL)) {
jeql .Lout_of_data
movl M_LEN(m),mlen # mlen = m->m_len;
movl M_DATA(m),data # data = mtod(m, uint8_t *);
.Lpost_initial_offset:
tstl mlen # if (mlen == 0)
jeql .Lthirdstmt # continue;
cmpl len,mlen # if (mlen > len)
jgeq 1f
movl len,mlen # mlen = len;
1: subl2 mlen,len # len -= mlen
cmpl mlen,$16 # if (mlen < 16)
jlss .Lshort_mbuf # goto short_mbuf;
#
#
blbc data,1f # if ((uintptr_t)data & 1) {
movzbl (data)+,tmp # tmp = *data++;
addl2 tmp,sum # sum += tmp;
adwc $0,sum
rotl $8,sum,sum # sum = (sum << 8 | sum >> 24);
xorl2 $1,byte_swapped # byte_swapped ^= 1;
decl mlen # mlen--;
1: # }
bbc $1,data,1f # if ((uintptr_t)data & 2) {
movzwl (data)+,tmp # tmp = *data++; (word *)
addl2 tmp,sum # sum += tmp;
adwc $0,sum
subl2 $2,mlen # mlen -= 2;
1: # }
#
#
2: subl2 $32,mlen # while ((mlen -= 32) >= 0) {
jlss 1f
addl2 (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc $0,sum
jbr 2b # }
1: addl2 $32,mlen # mlen += 32;
bbc $4,mlen,1f # if (mlen >= 16) {
addl2 (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc $0,sum
subl2 $16,mlen # mlen -= 16;
1: # }
.Lshort_mbuf: # short_mbuf:
bbc $3,mlen,1f # if (mlen >= 8) {
addl2 (data)+,sum # sum += *(uint32_t *)data;
adwc (data)+,sum # sum += *(uint32_t *)data;
adwc $0,sum
subl2 $8,mlen # mlen -= 8;
1: # }
bbc $2,mlen,1f # if (mlen >= 4) {
addl2 (data)+,sum # sum += *(uint32_t *)data;
adwc $0,sum
subl2 $4,mlen # mlen -= 4;
1: # }
bbc $1,mlen,1f # if (mlen >= 2) {
movzwl (data)+,tmp # tmp = *data++; (word *)
addl2 tmp,sum # sum += tmp;
adwc $0,sum
1: # }
blbc mlen,1f # if (mlen & 1) {
movzbl (data)+,tmp # tmp = *data++;
addl2 tmp,sum # sum += tmp;
adwc $0,sum
rotl $8,sum,sum # sum = (sum << 8 | sum >> 24);
xorl2 $1,byte_swapped # byte_swapped ^= 1;
1: # }
jbr .Lthirdstmt
.Lendsecond:
tstl len # if (len != 0)
jneq .Lout_of_data # goto out_of_data;
tstl byte_swapped # if (byte_swapped) {
jeql 1f
rotl $8,sum,sum # sum = (sum << 8 | sum >> 24);
1: rotl $16,sum,tmp # tmp = sum >> 16;
addw2 tmp,sum # sum(16) += tmp;
bicl2 $0xffff0000,sum # sum &= ~0xffff0000;
adwc $0,sum
xorl3 $0xffff,sum,%r0 # return (sum ^ 0xffff);
ret
.Lout_of_data:
pushab .Lin_cksum
calls $1,printf
mnegl $1,%r0
ret
.section .rodata
.Lin_cksum:
.asciz "in_cksum: out of data\n"