1/*
2 * User string length functions for kernel
3 *
4 * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and
8 * only version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
19 */
20
21#define isrc	r0
22#define max	r1	/*  Do not change!  */
23
24#define end	r2
25#define tmp1	r3
26
27#define obo	r6	/*  off-by-one  */
28#define start	r7
29#define mod8	r8
30#define dbuf    r15:14
31#define dcmp	r13:12
32
33/*
34 * The vector mask version of this turned out *really* badly.
35 * The hardware loop version also turned out *really* badly.
36 * Seems straight pointer arithmetic basically wins here.
37 */
38
39#define fname __strnlen_user
40
41	.text
42	.global fname
43	.type fname, @function
44	.p2align 5  /*  why?  */
45fname:
46	{
47		mod8 = and(isrc,#7);
48		end = add(isrc,max);
49		start = isrc;
50	}
51	{
52		P0 = cmp.eq(mod8,#0);
53		mod8 = and(end,#7);
54		dcmp = #0;
55		if (P0.new) jump:t dw_loop;	/*  fire up the oven  */
56	}
57
58alignment_loop:
59fail_1:	{
60		tmp1 = memb(start++#1);
61	}
62	{
63		P0 = cmp.eq(tmp1,#0);
64		if (P0.new) jump:nt exit_found;
65		P1 = cmp.gtu(end,start);
66		mod8 = and(start,#7);
67	}
68	{
69		if (!P1) jump exit_error;  /*  hit the end  */
70		P0 = cmp.eq(mod8,#0);
71	}
72	{
73		if (!P0) jump alignment_loop;
74	}
75
76
77
78dw_loop:
79fail_2:	{
80		dbuf = memd(start);
81		obo = add(start,#1);
82	}
83	{
84		P0 = vcmpb.eq(dbuf,dcmp);
85	}
86	{
87		tmp1 = P0;
88		P0 = cmp.gtu(end,start);
89	}
90	{
91		tmp1 = ct0(tmp1);
92		mod8 = and(end,#7);
93		if (!P0) jump end_check;
94	}
95	{
96		P0 = cmp.eq(tmp1,#32);
97		if (!P0.new) jump:nt exit_found;
98		if (!P0.new) start = add(obo,tmp1);
99	}
100	{
101		start = add(start,#8);
102		jump dw_loop;
103	}	/*  might be nice to combine these jumps...   */
104
105
106end_check:
107	{
108		P0 = cmp.gt(tmp1,mod8);
109		if (P0.new) jump:nt exit_error;	/*  neverfound!  */
110		start = add(obo,tmp1);
111	}
112
113exit_found:
114	{
115		R0 = sub(start,isrc);
116		jumpr R31;
117	}
118
119exit_error:
120	{
121		R0 = add(max,#1);
122		jumpr R31;
123	}
124
125	/*  Uh, what does the "fixup" return here?  */
126	.falign
127fix_1:
128	{
129		R0 = #0;
130		jumpr R31;
131	}
132
133	.size fname,.-fname
134
135
136.section __ex_table,"a"
137.long fail_1,fix_1
138.long fail_2,fix_1
139.previous
140