162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> 362306a36Sopenharmony_ci * Copyright (C) 2009 PetaLogix 462306a36Sopenharmony_ci * Copyright (C) 2007 LynuxWorks, Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 762306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 862306a36Sopenharmony_ci * for more details. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/linkage.h> 1362306a36Sopenharmony_ci#include <asm/page.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Loop unrolling for __copy_tofrom_user */ 1662306a36Sopenharmony_ci#define COPY(offset) \ 1762306a36Sopenharmony_ci1: lwi r4 , r6, 0x0000 + offset; \ 1862306a36Sopenharmony_ci2: lwi r19, r6, 0x0004 + offset; \ 1962306a36Sopenharmony_ci3: lwi r20, r6, 0x0008 + offset; \ 2062306a36Sopenharmony_ci4: lwi r21, r6, 0x000C + offset; \ 2162306a36Sopenharmony_ci5: lwi r22, r6, 0x0010 + offset; \ 2262306a36Sopenharmony_ci6: lwi r23, r6, 0x0014 + offset; \ 2362306a36Sopenharmony_ci7: lwi r24, r6, 0x0018 + offset; \ 2462306a36Sopenharmony_ci8: lwi r25, r6, 0x001C + offset; \ 2562306a36Sopenharmony_ci9: swi r4 , r5, 0x0000 + offset; \ 2662306a36Sopenharmony_ci10: swi r19, r5, 0x0004 + offset; \ 2762306a36Sopenharmony_ci11: swi r20, r5, 0x0008 + offset; \ 2862306a36Sopenharmony_ci12: swi r21, r5, 0x000C + offset; \ 2962306a36Sopenharmony_ci13: swi r22, r5, 0x0010 + offset; \ 3062306a36Sopenharmony_ci14: swi r23, r5, 0x0014 + offset; \ 3162306a36Sopenharmony_ci15: swi r24, r5, 0x0018 + offset; \ 3262306a36Sopenharmony_ci16: swi r25, r5, 0x001C + offset; \ 3362306a36Sopenharmony_ci .section __ex_table,"a"; \ 3462306a36Sopenharmony_ci .word 1b, 33f; \ 3562306a36Sopenharmony_ci .word 2b, 33f; \ 3662306a36Sopenharmony_ci .word 3b, 33f; \ 3762306a36Sopenharmony_ci .word 4b, 33f; \ 3862306a36Sopenharmony_ci .word 5b, 33f; \ 3962306a36Sopenharmony_ci .word 6b, 33f; \ 4062306a36Sopenharmony_ci .word 7b, 33f; \ 4162306a36Sopenharmony_ci .word 8b, 33f; \ 4262306a36Sopenharmony_ci .word 9b, 33f; \ 4362306a36Sopenharmony_ci .word 10b, 33f; \ 4462306a36Sopenharmony_ci .word 11b, 33f; \ 4562306a36Sopenharmony_ci .word 12b, 33f; \ 4662306a36Sopenharmony_ci .word 13b, 33f; \ 4762306a36Sopenharmony_ci .word 14b, 33f; \ 4862306a36Sopenharmony_ci .word 15b, 33f; \ 4962306a36Sopenharmony_ci .word 16b, 33f; \ 5062306a36Sopenharmony_ci .text 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define COPY_80(offset) \ 5362306a36Sopenharmony_ci COPY(0x00 + offset);\ 5462306a36Sopenharmony_ci COPY(0x20 + offset);\ 5562306a36Sopenharmony_ci COPY(0x40 + offset);\ 5662306a36Sopenharmony_ci COPY(0x60 + offset); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * int __copy_tofrom_user(char *to, char *from, int len) 6062306a36Sopenharmony_ci * Return: 6162306a36Sopenharmony_ci * 0 on success 6262306a36Sopenharmony_ci * number of not copied bytes on error 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci .text 6562306a36Sopenharmony_ci.globl __copy_tofrom_user; 6662306a36Sopenharmony_ci.type __copy_tofrom_user, @function 6762306a36Sopenharmony_ci.align 4; 6862306a36Sopenharmony_ci__copy_tofrom_user: 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * r5 - to 7162306a36Sopenharmony_ci * r6 - from 7262306a36Sopenharmony_ci * r7, r3 - count 7362306a36Sopenharmony_ci * r4 - tempval 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci beqid r7, 0f /* zero size is not likely */ 7662306a36Sopenharmony_ci or r3, r5, r6 /* find if is any to/from unaligned */ 7762306a36Sopenharmony_ci or r3, r3, r7 /* find if count is unaligned */ 7862306a36Sopenharmony_ci andi r3, r3, 0x3 /* mask last 3 bits */ 7962306a36Sopenharmony_ci bneid r3, bu1 /* if r3 is not zero then byte copying */ 8062306a36Sopenharmony_ci or r3, r0, r0 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci rsubi r3, r7, PAGE_SIZE /* detect PAGE_SIZE */ 8362306a36Sopenharmony_ci beqid r3, page; 8462306a36Sopenharmony_ci or r3, r0, r0 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciw1: lw r4, r6, r3 /* at least one 4 byte copy */ 8762306a36Sopenharmony_ciw2: sw r4, r5, r3 8862306a36Sopenharmony_ci addik r7, r7, -4 8962306a36Sopenharmony_ci bneid r7, w1 9062306a36Sopenharmony_ci addik r3, r3, 4 9162306a36Sopenharmony_ci addik r3, r7, 0 9262306a36Sopenharmony_ci rtsd r15, 8 9362306a36Sopenharmony_ci nop 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci .section __ex_table,"a" 9662306a36Sopenharmony_ci .word w1, 0f; 9762306a36Sopenharmony_ci .word w2, 0f; 9862306a36Sopenharmony_ci .text 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci.align 4 /* Alignment is important to keep icache happy */ 10162306a36Sopenharmony_cipage: /* Create room on stack and save registers for storing values */ 10262306a36Sopenharmony_ci addik r1, r1, -40 10362306a36Sopenharmony_ci swi r5, r1, 0 10462306a36Sopenharmony_ci swi r6, r1, 4 10562306a36Sopenharmony_ci swi r7, r1, 8 10662306a36Sopenharmony_ci swi r19, r1, 12 10762306a36Sopenharmony_ci swi r20, r1, 16 10862306a36Sopenharmony_ci swi r21, r1, 20 10962306a36Sopenharmony_ci swi r22, r1, 24 11062306a36Sopenharmony_ci swi r23, r1, 28 11162306a36Sopenharmony_ci swi r24, r1, 32 11262306a36Sopenharmony_ci swi r25, r1, 36 11362306a36Sopenharmony_ciloop: /* r4, r19, r20, r21, r22, r23, r24, r25 are used for storing values */ 11462306a36Sopenharmony_ci /* Loop unrolling to get performance boost */ 11562306a36Sopenharmony_ci COPY_80(0x000); 11662306a36Sopenharmony_ci COPY_80(0x080); 11762306a36Sopenharmony_ci COPY_80(0x100); 11862306a36Sopenharmony_ci COPY_80(0x180); 11962306a36Sopenharmony_ci /* copy loop */ 12062306a36Sopenharmony_ci addik r6, r6, 0x200 12162306a36Sopenharmony_ci addik r7, r7, -0x200 12262306a36Sopenharmony_ci bneid r7, loop 12362306a36Sopenharmony_ci addik r5, r5, 0x200 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Restore register content */ 12662306a36Sopenharmony_ci lwi r5, r1, 0 12762306a36Sopenharmony_ci lwi r6, r1, 4 12862306a36Sopenharmony_ci lwi r7, r1, 8 12962306a36Sopenharmony_ci lwi r19, r1, 12 13062306a36Sopenharmony_ci lwi r20, r1, 16 13162306a36Sopenharmony_ci lwi r21, r1, 20 13262306a36Sopenharmony_ci lwi r22, r1, 24 13362306a36Sopenharmony_ci lwi r23, r1, 28 13462306a36Sopenharmony_ci lwi r24, r1, 32 13562306a36Sopenharmony_ci lwi r25, r1, 36 13662306a36Sopenharmony_ci addik r1, r1, 40 13762306a36Sopenharmony_ci /* return back */ 13862306a36Sopenharmony_ci addik r3, r0, 0 13962306a36Sopenharmony_ci rtsd r15, 8 14062306a36Sopenharmony_ci nop 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* Fault case - return temp count */ 14362306a36Sopenharmony_ci33: 14462306a36Sopenharmony_ci addik r3, r7, 0 14562306a36Sopenharmony_ci /* Restore register content */ 14662306a36Sopenharmony_ci lwi r5, r1, 0 14762306a36Sopenharmony_ci lwi r6, r1, 4 14862306a36Sopenharmony_ci lwi r7, r1, 8 14962306a36Sopenharmony_ci lwi r19, r1, 12 15062306a36Sopenharmony_ci lwi r20, r1, 16 15162306a36Sopenharmony_ci lwi r21, r1, 20 15262306a36Sopenharmony_ci lwi r22, r1, 24 15362306a36Sopenharmony_ci lwi r23, r1, 28 15462306a36Sopenharmony_ci lwi r24, r1, 32 15562306a36Sopenharmony_ci lwi r25, r1, 36 15662306a36Sopenharmony_ci addik r1, r1, 40 15762306a36Sopenharmony_ci /* return back */ 15862306a36Sopenharmony_ci rtsd r15, 8 15962306a36Sopenharmony_ci nop 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci.align 4 /* Alignment is important to keep icache happy */ 16262306a36Sopenharmony_cibu1: lbu r4,r6,r3 16362306a36Sopenharmony_cibu2: sb r4,r5,r3 16462306a36Sopenharmony_ci addik r7,r7,-1 16562306a36Sopenharmony_ci bneid r7,bu1 16662306a36Sopenharmony_ci addik r3,r3,1 /* delay slot */ 16762306a36Sopenharmony_ci0: 16862306a36Sopenharmony_ci addik r3,r7,0 16962306a36Sopenharmony_ci rtsd r15,8 17062306a36Sopenharmony_ci nop 17162306a36Sopenharmony_ci .size __copy_tofrom_user, . - __copy_tofrom_user 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci .section __ex_table,"a" 17462306a36Sopenharmony_ci .word bu1, 0b; 17562306a36Sopenharmony_ci .word bu2, 0b; 17662306a36Sopenharmony_ci .text 177