1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2009, Wind River Systems Inc
7 * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
8 */
9
10#include <linux/export.h>
11#include <linux/uaccess.h>
12
13asm(".global	__copy_from_user\n"
14	"   .type __copy_from_user, @function\n"
15	"__copy_from_user:\n"
16	"   movi  r2,7\n"
17	"   mov   r3,r4\n"
18	"   bge   r2,r6,1f\n"
19	"   xor   r2,r4,r5\n"
20	"   andi  r2,r2,3\n"
21	"   movi  r7,3\n"
22	"   beq   r2,zero,4f\n"
23	"1: addi  r6,r6,-1\n"
24	"   movi  r2,-1\n"
25	"   beq   r6,r2,3f\n"
26	"   mov   r7,r2\n"
27	"2: ldbu  r2,0(r5)\n"
28	"   addi  r6,r6,-1\n"
29	"   addi  r5,r5,1\n"
30	"   stb   r2,0(r3)\n"
31	"   addi  r3,r3,1\n"
32	"   bne   r6,r7,2b\n"
33	"3:\n"
34	"   addi  r2,r6,1\n"
35	"   ret\n"
36	"13:mov   r2,r6\n"
37	"   ret\n"
38	"4: andi  r2,r4,1\n"
39	"   cmpeq r2,r2,zero\n"
40	"   beq   r2,zero,7f\n"
41	"5: andi  r2,r3,2\n"
42	"   beq   r2,zero,6f\n"
43	"9: ldhu  r2,0(r5)\n"
44	"   addi  r6,r6,-2\n"
45	"   addi  r5,r5,2\n"
46	"   sth   r2,0(r3)\n"
47	"   addi  r3,r3,2\n"
48	"6: bge   r7,r6,1b\n"
49	"10:ldw   r2,0(r5)\n"
50	"   addi  r6,r6,-4\n"
51	"   addi  r5,r5,4\n"
52	"   stw   r2,0(r3)\n"
53	"   addi  r3,r3,4\n"
54	"   br    6b\n"
55	"7: ldbu  r2,0(r5)\n"
56	"   addi  r6,r6,-1\n"
57	"   addi  r5,r5,1\n"
58	"   addi  r3,r4,1\n"
59	"   stb   r2,0(r4)\n"
60	"   br    5b\n"
61	".section __ex_table,\"a\"\n"
62	".word 2b,3b\n"
63	".word 9b,13b\n"
64	".word 10b,13b\n"
65	".word 7b,13b\n"
66	".previous\n"
67	);
68EXPORT_SYMBOL(__copy_from_user);
69
70asm(
71	"   .global __copy_to_user\n"
72	"   .type __copy_to_user, @function\n"
73	"__copy_to_user:\n"
74	"   movi  r2,7\n"
75	"   mov   r3,r4\n"
76	"   bge   r2,r6,1f\n"
77	"   xor   r2,r4,r5\n"
78	"   andi  r2,r2,3\n"
79	"   movi  r7,3\n"
80	"   beq   r2,zero,4f\n"
81	/* Bail if we try to copy zero bytes  */
82	"1: addi  r6,r6,-1\n"
83	"   movi  r2,-1\n"
84	"   beq   r6,r2,3f\n"
85	/* Copy byte by byte for small copies and if src^dst != 0 */
86	"   mov   r7,r2\n"
87	"2: ldbu  r2,0(r5)\n"
88	"   addi  r5,r5,1\n"
89	"9: stb   r2,0(r3)\n"
90	"   addi  r6,r6,-1\n"
91	"   addi  r3,r3,1\n"
92	"   bne   r6,r7,2b\n"
93	"3: addi  r2,r6,1\n"
94	"   ret\n"
95	"13:mov   r2,r6\n"
96	"   ret\n"
97	/*  If 'to' is an odd address byte copy */
98	"4: andi  r2,r4,1\n"
99	"   cmpeq r2,r2,zero\n"
100	"   beq   r2,zero,7f\n"
101	/* If 'to' is not divideable by four copy halfwords */
102	"5: andi  r2,r3,2\n"
103	"   beq   r2,zero,6f\n"
104	"   ldhu  r2,0(r5)\n"
105	"   addi  r5,r5,2\n"
106	"10:sth   r2,0(r3)\n"
107	"   addi  r6,r6,-2\n"
108	"   addi  r3,r3,2\n"
109	/* Copy words */
110	"6: bge   r7,r6,1b\n"
111	"   ldw   r2,0(r5)\n"
112	"   addi  r5,r5,4\n"
113	"11:stw   r2,0(r3)\n"
114	"   addi  r6,r6,-4\n"
115	"   addi  r3,r3,4\n"
116	"   br    6b\n"
117	/* Copy remaining bytes */
118	"7: ldbu  r2,0(r5)\n"
119	"   addi  r5,r5,1\n"
120	"   addi  r3,r4,1\n"
121	"12: stb  r2,0(r4)\n"
122	"   addi  r6,r6,-1\n"
123	"   br    5b\n"
124	".section __ex_table,\"a\"\n"
125	".word 9b,3b\n"
126	".word 10b,13b\n"
127	".word 11b,13b\n"
128	".word 12b,13b\n"
129	".previous\n");
130EXPORT_SYMBOL(__copy_to_user);
131
132long strncpy_from_user(char *__to, const char __user *__from, long __len)
133{
134	int l = strnlen_user(__from, __len);
135	int is_zt = 1;
136
137	if (l > __len) {
138		is_zt = 0;
139		l = __len;
140	}
141
142	if (l == 0 || copy_from_user(__to, __from, l))
143		return -EFAULT;
144
145	if (is_zt)
146		l--;
147	return l;
148}
149
150long strnlen_user(const char __user *s, long n)
151{
152	long i;
153
154	for (i = 0; i < n; i++) {
155		char c;
156
157		if (get_user(c, s + i) == -EFAULT)
158			return 0;
159		if (c == 0)
160			return i + 1;
161	}
162	return n + 1;
163}
164