Commit | Line | Data |
---|---|---|
5ccc6af5 LFT |
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 | ||
13 | asm(".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 | ); | |
68 | EXPORT_SYMBOL(__copy_from_user); | |
69 | ||
70 | asm( | |
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"); | |
130 | EXPORT_SYMBOL(__copy_to_user); | |
131 | ||
132 | long 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 | ||
150 | long 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 | } |