1/* 2 * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> 3 * Copyright (C) 2009 PetaLogix 4 * Copyright (C) 2007 LynuxWorks, Inc. 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 */ 10 11#include <linux/errno.h> 12#include <linux/linkage.h> 13#include <asm/page.h> 14 15/* 16 * int __strncpy_user(char *to, char *from, int len); 17 * 18 * Returns: 19 * -EFAULT for an exception 20 * len if we hit the buffer limit 21 * bytes copied 22 */ 23 24 .text 25.globl __strncpy_user; 26.type __strncpy_user, @function 27.align 4; 28__strncpy_user: 29 30 /* 31 * r5 - to 32 * r6 - from 33 * r7 - len 34 * r3 - temp count 35 * r4 - temp val 36 */ 37 beqid r7,3f 38 addik r3,r7,0 /* temp_count = len */ 391: 40 lbu r4,r6,r0 41 sb r4,r5,r0 42 43 addik r3,r3,-1 44 beqi r3,2f /* break on len */ 45 46 addik r5,r5,1 47 bneid r4,1b 48 addik r6,r6,1 /* delay slot */ 49 addik r3,r3,1 /* undo "temp_count--" */ 502: 51 rsubk r3,r3,r7 /* temp_count = len - temp_count */ 523: 53 rtsd r15,8 54 nop 55 .size __strncpy_user, . - __strncpy_user 56 57 .section .fixup, "ax" 58 .align 2 594: 60 brid 3b 61 addik r3,r0, -EFAULT 62 63 .section __ex_table, "a" 64 .word 1b,4b 65 66/* 67 * int __strnlen_user(char __user *str, int maxlen); 68 * 69 * Returns: 70 * 0 on error 71 * maxlen + 1 if no NUL byte found within maxlen bytes 72 * size of the string (including NUL byte) 73 */ 74 75 .text 76.globl __strnlen_user; 77.type __strnlen_user, @function 78.align 4; 79__strnlen_user: 80 beqid r6,3f 81 addik r3,r6,0 821: 83 lbu r4,r5,r0 84 beqid r4,2f /* break on NUL */ 85 addik r3,r3,-1 /* delay slot */ 86 87 bneid r3,1b 88 addik r5,r5,1 /* delay slot */ 89 90 addik r3,r3,-1 /* for break on len */ 912: 92 rsubk r3,r3,r6 933: 94 rtsd r15,8 95 nop 96 .size __strnlen_user, . - __strnlen_user 97 98 .section .fixup,"ax" 994: 100 brid 3b 101 addk r3,r0,r0 102 103 .section __ex_table,"a" 104 .word 1b,4b 105 106/* Loop unrolling for __copy_tofrom_user */ 107#define COPY(offset) \ 1081: lwi r4 , r6, 0x0000 + offset; \ 1092: lwi r19, r6, 0x0004 + offset; \ 1103: lwi r20, r6, 0x0008 + offset; \ 1114: lwi r21, r6, 0x000C + offset; \ 1125: lwi r22, r6, 0x0010 + offset; \ 1136: lwi r23, r6, 0x0014 + offset; \ 1147: lwi r24, r6, 0x0018 + offset; \ 1158: lwi r25, r6, 0x001C + offset; \ 1169: swi r4 , r5, 0x0000 + offset; \ 11710: swi r19, r5, 0x0004 + offset; \ 11811: swi r20, r5, 0x0008 + offset; \ 11912: swi r21, r5, 0x000C + offset; \ 12013: swi r22, r5, 0x0010 + offset; \ 12114: swi r23, r5, 0x0014 + offset; \ 12215: swi r24, r5, 0x0018 + offset; \ 12316: swi r25, r5, 0x001C + offset; \ 124 .section __ex_table,"a"; \ 125 .word 1b, 0f; \ 126 .word 2b, 0f; \ 127 .word 3b, 0f; \ 128 .word 4b, 0f; \ 129 .word 5b, 0f; \ 130 .word 6b, 0f; \ 131 .word 7b, 0f; \ 132 .word 8b, 0f; \ 133 .word 9b, 0f; \ 134 .word 10b, 0f; \ 135 .word 11b, 0f; \ 136 .word 12b, 0f; \ 137 .word 13b, 0f; \ 138 .word 14b, 0f; \ 139 .word 15b, 0f; \ 140 .word 16b, 0f; \ 141 .text 142 143#define COPY_80(offset) \ 144 COPY(0x00 + offset);\ 145 COPY(0x20 + offset);\ 146 COPY(0x40 + offset);\ 147 COPY(0x60 + offset); 148 149/* 150 * int __copy_tofrom_user(char *to, char *from, int len) 151 * Return: 152 * 0 on success 153 * number of not copied bytes on error 154 */ 155 .text 156.globl __copy_tofrom_user; 157.type __copy_tofrom_user, @function 158.align 4; 159__copy_tofrom_user: 160 /* 161 * r5 - to 162 * r6 - from 163 * r7, r3 - count 164 * r4 - tempval 165 */ 166 beqid r7, 0f /* zero size is not likely */ 167 or r3, r5, r6 /* find if is any to/from unaligned */ 168 or r3, r3, r7 /* find if count is unaligned */ 169 andi r3, r3, 0x3 /* mask last 3 bits */ 170 bneid r3, bu1 /* if r3 is not zero then byte copying */ 171 or r3, r0, r0 172 173 rsubi r3, r7, PAGE_SIZE /* detect PAGE_SIZE */ 174 beqid r3, page; 175 or r3, r0, r0 176 177w1: lw r4, r6, r3 /* at least one 4 byte copy */ 178w2: sw r4, r5, r3 179 addik r7, r7, -4 180 bneid r7, w1 181 addik r3, r3, 4 182 addik r3, r7, 0 183 rtsd r15, 8 184 nop 185 186 .section __ex_table,"a" 187 .word w1, 0f; 188 .word w2, 0f; 189 .text 190 191.align 4 /* Alignment is important to keep icache happy */ 192page: /* Create room on stack and save registers for storign values */ 193 addik r1, r1, -32 194 swi r19, r1, 4 195 swi r20, r1, 8 196 swi r21, r1, 12 197 swi r22, r1, 16 198 swi r23, r1, 20 199 swi r24, r1, 24 200 swi r25, r1, 28 201loop: /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */ 202 /* Loop unrolling to get performance boost */ 203 COPY_80(0x000); 204 COPY_80(0x080); 205 COPY_80(0x100); 206 COPY_80(0x180); 207 /* copy loop */ 208 addik r6, r6, 0x200 209 addik r7, r7, -0x200 210 bneid r7, loop 211 addik r5, r5, 0x200 212 /* Restore register content */ 213 lwi r19, r1, 4 214 lwi r20, r1, 8 215 lwi r21, r1, 12 216 lwi r22, r1, 16 217 lwi r23, r1, 20 218 lwi r24, r1, 24 219 lwi r25, r1, 28 220 addik r1, r1, 32 221 /* return back */ 222 addik r3, r7, 0 223 rtsd r15, 8 224 nop 225 226.align 4 /* Alignment is important to keep icache happy */ 227bu1: lbu r4,r6,r3 228bu2: sb r4,r5,r3 229 addik r7,r7,-1 230 bneid r7,bu1 231 addik r3,r3,1 /* delay slot */ 2320: 233 addik r3,r7,0 234 rtsd r15,8 235 nop 236 .size __copy_tofrom_user, . - __copy_tofrom_user 237 238 .section __ex_table,"a" 239 .word bu1, 0b; 240 .word bu2, 0b; 241 .text 242