Commit | Line | Data |
---|---|---|
b920de1b DH |
1 | /* MN10300 Userspace accessor functions |
2 | * | |
3 | * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. | |
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public Licence | |
9 | * as published by the Free Software Foundation; either version | |
10 | * 2 of the Licence, or (at your option) any later version. | |
11 | */ | |
12 | #include <asm/uaccess.h> | |
13 | ||
14 | unsigned long | |
15 | __generic_copy_to_user(void *to, const void *from, unsigned long n) | |
16 | { | |
17 | if (access_ok(VERIFY_WRITE, to, n)) | |
18 | __copy_user(to, from, n); | |
19 | return n; | |
20 | } | |
21 | ||
22 | unsigned long | |
23 | __generic_copy_from_user(void *to, const void *from, unsigned long n) | |
24 | { | |
25 | if (access_ok(VERIFY_READ, from, n)) | |
26 | __copy_user_zeroing(to, from, n); | |
27 | return n; | |
28 | } | |
29 | ||
30 | /* | |
31 | * Copy a null terminated string from userspace. | |
32 | */ | |
33 | #define __do_strncpy_from_user(dst, src, count, res) \ | |
34 | do { \ | |
35 | int w; \ | |
36 | asm volatile( \ | |
37 | " mov %1,%0\n" \ | |
38 | " cmp 0,%1\n" \ | |
39 | " beq 2f\n" \ | |
40 | "0:\n" \ | |
41 | " movbu (%5),%2\n" \ | |
42 | "1:\n" \ | |
43 | " movbu %2,(%6)\n" \ | |
44 | " inc %5\n" \ | |
45 | " inc %6\n" \ | |
46 | " cmp 0,%2\n" \ | |
47 | " beq 2f\n" \ | |
48 | " add -1,%1\n" \ | |
49 | " bne 0b\n" \ | |
50 | "2:\n" \ | |
51 | " sub %1,%0\n" \ | |
52 | "3:\n" \ | |
53 | " .section .fixup,\"ax\"\n" \ | |
54 | "4:\n" \ | |
55 | " mov %3,%0\n" \ | |
56 | " jmp 3b\n" \ | |
57 | " .previous\n" \ | |
58 | " .section __ex_table,\"a\"\n" \ | |
59 | " .balign 4\n" \ | |
60 | " .long 0b,4b\n" \ | |
61 | " .long 1b,4b\n" \ | |
62 | " .previous" \ | |
63 | :"=&r"(res), "=r"(count), "=&r"(w) \ | |
64 | :"i"(-EFAULT), "1"(count), "a"(src), "a"(dst) \ | |
d6bb7a1a | 65 | : "memory", "cc"); \ |
b920de1b DH |
66 | } while (0) |
67 | ||
68 | long | |
69 | __strncpy_from_user(char *dst, const char *src, long count) | |
70 | { | |
71 | long res; | |
72 | __do_strncpy_from_user(dst, src, count, res); | |
73 | return res; | |
74 | } | |
75 | ||
76 | long | |
77 | strncpy_from_user(char *dst, const char *src, long count) | |
78 | { | |
79 | long res = -EFAULT; | |
80 | if (access_ok(VERIFY_READ, src, 1)) | |
81 | __do_strncpy_from_user(dst, src, count, res); | |
82 | return res; | |
83 | } | |
84 | ||
85 | ||
86 | /* | |
87 | * Clear a userspace memory | |
88 | */ | |
89 | #define __do_clear_user(addr, size) \ | |
90 | do { \ | |
91 | int w; \ | |
92 | asm volatile( \ | |
93 | " cmp 0,%0\n" \ | |
94 | " beq 1f\n" \ | |
95 | " clr %1\n" \ | |
96 | "0: movbu %1,(%3,%2)\n" \ | |
97 | " inc %3\n" \ | |
98 | " cmp %0,%3\n" \ | |
99 | " bne 0b\n" \ | |
100 | "1:\n" \ | |
101 | " sub %3,%0\n" \ | |
102 | "2:\n" \ | |
103 | ".section .fixup,\"ax\"\n" \ | |
104 | "3: jmp 2b\n" \ | |
105 | ".previous\n" \ | |
106 | ".section __ex_table,\"a\"\n" \ | |
107 | " .balign 4\n" \ | |
108 | " .long 0b,3b\n" \ | |
109 | ".previous\n" \ | |
110 | : "+r"(size), "=&r"(w) \ | |
111 | : "a"(addr), "d"(0) \ | |
d6bb7a1a | 112 | : "memory", "cc"); \ |
b920de1b DH |
113 | } while (0) |
114 | ||
115 | unsigned long | |
116 | __clear_user(void *to, unsigned long n) | |
117 | { | |
118 | __do_clear_user(to, n); | |
119 | return n; | |
120 | } | |
121 | ||
122 | unsigned long | |
123 | clear_user(void *to, unsigned long n) | |
124 | { | |
125 | if (access_ok(VERIFY_WRITE, to, n)) | |
126 | __do_clear_user(to, n); | |
127 | return n; | |
128 | } | |
129 | ||
130 | /* | |
131 | * Return the size of a string (including the ending 0) | |
132 | * | |
133 | * Return 0 on exception, a value greater than N if too long | |
134 | */ | |
135 | long strnlen_user(const char *s, long n) | |
136 | { | |
137 | unsigned long res, w; | |
138 | ||
139 | if (!__addr_ok(s)) | |
140 | return 0; | |
141 | ||
142 | if (n < 0 || n + (u_long) s > current_thread_info()->addr_limit.seg) | |
143 | n = current_thread_info()->addr_limit.seg - (u_long)s; | |
144 | ||
145 | asm volatile( | |
146 | "0: cmp %4,%0\n" | |
147 | " beq 2f\n" | |
148 | "1: movbu (%0,%3),%1\n" | |
149 | " inc %0\n" | |
150 | " cmp 0,%1\n" | |
151 | " beq 3f\n" | |
152 | " bra 0b\n" | |
153 | "2: clr %0\n" | |
154 | "3:\n" | |
155 | ".section .fixup,\"ax\"\n" | |
156 | "4: jmp 2b\n" | |
157 | ".previous\n" | |
158 | ".section __ex_table,\"a\"\n" | |
159 | " .balign 4\n" | |
160 | " .long 1b,4b\n" | |
161 | ".previous\n" | |
162 | :"=d"(res), "=&r"(w) | |
163 | :"0"(0), "a"(s), "r"(n) | |
d6bb7a1a | 164 | : "memory", "cc"); |
b920de1b DH |
165 | return res; |
166 | } |