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 beqid r4,2f 42 sb r4,r5,r0 43 44 addik r5,r5,1 45 addik r6,r6,1 /* delay slot */ 46 47 addik r3,r3,-1 48 bnei r3,1b /* break on len */ 492: 50 rsubk r3,r3,r7 /* temp_count = len - temp_count */ 513: 52 rtsd r15,8 53 nop 54 .size __strncpy_user, . - __strncpy_user 55 56 .section .fixup, "ax" 57 .align 2 584: 59 brid 3b 60 addik r3,r0, -EFAULT 61 62 .section __ex_table, "a" 63 .word 1b,4b 64 65/* 66 * int __strnlen_user(char __user *str, int maxlen); 67 * 68 * Returns: 69 * 0 on error 70 * maxlen + 1 if no NUL byte found within maxlen bytes 71 * size of the string (including NUL byte) 72 */ 73 74 .text 75.globl __strnlen_user; 76.type __strnlen_user, @function 77.align 4; 78__strnlen_user: 79 beqid r6,3f 80 addik r3,r6,0 811: 82 lbu r4,r5,r0 83 beqid r4,2f /* break on NUL */ 84 addik r3,r3,-1 /* delay slot */ 85 86 bneid r3,1b 87 addik r5,r5,1 /* delay slot */ 88 89 addik r3,r3,-1 /* for break on len */ 902: 91 rsubk r3,r3,r6 923: 93 rtsd r15,8 94 nop 95 .size __strnlen_user, . - __strnlen_user 96 97 .section .fixup,"ax" 984: 99 brid 3b 100 addk r3,r0,r0 101 102 .section __ex_table,"a" 103 .word 1b,4b 104 105/* Loop unrolling for __copy_tofrom_user */ 106#define COPY(offset) \ 1071: lwi r4 , r6, 0x0000 + offset; \ 1082: lwi r19, r6, 0x0004 + offset; \ 1093: lwi r20, r6, 0x0008 + offset; \ 1104: lwi r21, r6, 0x000C + offset; \ 1115: lwi r22, r6, 0x0010 + offset; \ 1126: lwi r23, r6, 0x0014 + offset; \ 1137: lwi r24, r6, 0x0018 + offset; \ 1148: lwi r25, r6, 0x001C + offset; \ 1159: swi r4 , r5, 0x0000 + offset; \ 11610: swi r19, r5, 0x0004 + offset; \ 11711: swi r20, r5, 0x0008 + offset; \ 11812: swi r21, r5, 0x000C + offset; \ 11913: swi r22, r5, 0x0010 + offset; \ 12014: swi r23, r5, 0x0014 + offset; \ 12115: swi r24, r5, 0x0018 + offset; \ 12216: swi r25, r5, 0x001C + offset; \ 123 .section __ex_table,"a"; \ 124 .word 1b, 33f; \ 125 .word 2b, 33f; \ 126 .word 3b, 33f; \ 127 .word 4b, 33f; \ 128 .word 5b, 33f; \ 129 .word 6b, 33f; \ 130 .word 7b, 33f; \ 131 .word 8b, 33f; \ 132 .word 9b, 33f; \ 133 .word 10b, 33f; \ 134 .word 11b, 33f; \ 135 .word 12b, 33f; \ 136 .word 13b, 33f; \ 137 .word 14b, 33f; \ 138 .word 15b, 33f; \ 139 .word 16b, 33f; \ 140 .text 141 142#define COPY_80(offset) \ 143 COPY(0x00 + offset);\ 144 COPY(0x20 + offset);\ 145 COPY(0x40 + offset);\ 146 COPY(0x60 + offset); 147 148/* 149 * int __copy_tofrom_user(char *to, char *from, int len) 150 * Return: 151 * 0 on success 152 * number of not copied bytes on error 153 */ 154 .text 155.globl __copy_tofrom_user; 156.type __copy_tofrom_user, @function 157.align 4; 158__copy_tofrom_user: 159 /* 160 * r5 - to 161 * r6 - from 162 * r7, r3 - count 163 * r4 - tempval 164 */ 165 beqid r7, 0f /* zero size is not likely */ 166 or r3, r5, r6 /* find if is any to/from unaligned */ 167 or r3, r3, r7 /* find if count is unaligned */ 168 andi r3, r3, 0x3 /* mask last 3 bits */ 169 bneid r3, bu1 /* if r3 is not zero then byte copying */ 170 or r3, r0, r0 171 172 rsubi r3, r7, PAGE_SIZE /* detect PAGE_SIZE */ 173 beqid r3, page; 174 or r3, r0, r0 175 176w1: lw r4, r6, r3 /* at least one 4 byte copy */ 177w2: sw r4, r5, r3 178 addik r7, r7, -4 179 bneid r7, w1 180 addik r3, r3, 4 181 addik r3, r7, 0 182 rtsd r15, 8 183 nop 184 185 .section __ex_table,"a" 186 .word w1, 0f; 187 .word w2, 0f; 188 .text 189 190.align 4 /* Alignment is important to keep icache happy */ 191page: /* Create room on stack and save registers for storing values */ 192 addik r1, r1, -40 193 swi r5, r1, 0 194 swi r6, r1, 4 195 swi r7, r1, 8 196 swi r19, r1, 12 197 swi r20, r1, 16 198 swi r21, r1, 20 199 swi r22, r1, 24 200 swi r23, r1, 28 201 swi r24, r1, 32 202 swi r25, r1, 36 203loop: /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */ 204 /* Loop unrolling to get performance boost */ 205 COPY_80(0x000); 206 COPY_80(0x080); 207 COPY_80(0x100); 208 COPY_80(0x180); 209 /* copy loop */ 210 addik r6, r6, 0x200 211 addik r7, r7, -0x200 212 bneid r7, loop 213 addik r5, r5, 0x200 214 215 /* Restore register content */ 216 lwi r5, r1, 0 217 lwi r6, r1, 4 218 lwi r7, r1, 8 219 lwi r19, r1, 12 220 lwi r20, r1, 16 221 lwi r21, r1, 20 222 lwi r22, r1, 24 223 lwi r23, r1, 28 224 lwi r24, r1, 32 225 lwi r25, r1, 36 226 addik r1, r1, 40 227 /* return back */ 228 addik r3, r0, 0 229 rtsd r15, 8 230 nop 231 232/* Fault case - return temp count */ 23333: 234 addik r3, r7, 0 235 /* Restore register content */ 236 lwi r5, r1, 0 237 lwi r6, r1, 4 238 lwi r7, r1, 8 239 lwi r19, r1, 12 240 lwi r20, r1, 16 241 lwi r21, r1, 20 242 lwi r22, r1, 24 243 lwi r23, r1, 28 244 lwi r24, r1, 32 245 lwi r25, r1, 36 246 addik r1, r1, 40 247 /* return back */ 248 rtsd r15, 8 249 nop 250 251.align 4 /* Alignment is important to keep icache happy */ 252bu1: lbu r4,r6,r3 253bu2: sb r4,r5,r3 254 addik r7,r7,-1 255 bneid r7,bu1 256 addik r3,r3,1 /* delay slot */ 2570: 258 addik r3,r7,0 259 rtsd r15,8 260 nop 261 .size __copy_tofrom_user, . - __copy_tofrom_user 262 263 .section __ex_table,"a" 264 .word bu1, 0b; 265 .word bu2, 0b; 266 .text 267