1/* 2 * User string length functions for kernel 3 * 4 * Copyright (c) 2010-2011, The Linux Foundation. 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