aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/lib')
-rw-r--r--arch/s390/lib/uaccess_mvcos.c26
-rw-r--r--arch/s390/lib/uaccess_pt.c129
-rw-r--r--arch/s390/lib/uaccess_std.c48
3 files changed, 124 insertions, 79 deletions
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 2443ae476e33..1829742bf479 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -162,19 +162,19 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
162 162
163static size_t strnlen_user_mvcos(size_t count, const char __user *src) 163static size_t strnlen_user_mvcos(size_t count, const char __user *src)
164{ 164{
165 size_t done, len, offset, len_str;
165 char buf[256]; 166 char buf[256];
166 int rc;
167 size_t done, len, len_str;
168 167
169 done = 0; 168 done = 0;
170 do { 169 do {
171 len = min(count - done, (size_t) 256); 170 offset = (size_t)src & ~PAGE_MASK;
172 rc = uaccess.copy_from_user(len, src + done, buf); 171 len = min(256UL, PAGE_SIZE - offset);
173 if (unlikely(rc == len)) 172 len = min(count - done, len);
173 if (copy_from_user_mvcos(len, src, buf))
174 return 0; 174 return 0;
175 len -= rc;
176 len_str = strnlen(buf, len); 175 len_str = strnlen(buf, len);
177 done += len_str; 176 done += len_str;
177 src += len_str;
178 } while ((len_str == len) && (done < count)); 178 } while ((len_str == len) && (done < count));
179 return done + 1; 179 return done + 1;
180} 180}
@@ -182,18 +182,20 @@ static size_t strnlen_user_mvcos(size_t count, const char __user *src)
182static size_t strncpy_from_user_mvcos(size_t count, const char __user *src, 182static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
183 char *dst) 183 char *dst)
184{ 184{
185 int rc; 185 size_t done, len, offset, len_str;
186 size_t done, len, len_str;
187 186
187 if (unlikely(!count))
188 return 0;
188 done = 0; 189 done = 0;
189 do { 190 do {
190 len = min(count - done, (size_t) 4096); 191 offset = (size_t)src & ~PAGE_MASK;
191 rc = uaccess.copy_from_user(len, src + done, dst); 192 len = min(count - done, PAGE_SIZE - offset);
192 if (unlikely(rc == len)) 193 if (copy_from_user_mvcos(len, src, dst))
193 return -EFAULT; 194 return -EFAULT;
194 len -= rc;
195 len_str = strnlen(dst, len); 195 len_str = strnlen(dst, len);
196 done += len_str; 196 done += len_str;
197 src += len_str;
198 dst += len_str;
197 } while ((len_str == len) && (done < count)); 199 } while ((len_str == len) && (done < count));
198 return done; 200 return done;
199} 201}
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index a70ee84c0241..dff631d34b45 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -14,6 +14,63 @@
14#include <asm/futex.h> 14#include <asm/futex.h>
15#include "uaccess.h" 15#include "uaccess.h"
16 16
17#ifndef CONFIG_64BIT
18#define AHI "ahi"
19#define SLR "slr"
20#else
21#define AHI "aghi"
22#define SLR "slgr"
23#endif
24
25static size_t strnlen_kernel(size_t count, const char __user *src)
26{
27 register unsigned long reg0 asm("0") = 0UL;
28 unsigned long tmp1, tmp2;
29
30 asm volatile(
31 " la %2,0(%1)\n"
32 " la %3,0(%0,%1)\n"
33 " "SLR" %0,%0\n"
34 "0: srst %3,%2\n"
35 " jo 0b\n"
36 " la %0,1(%3)\n" /* strnlen_kernel results includes \0 */
37 " "SLR" %0,%1\n"
38 "1:\n"
39 EX_TABLE(0b,1b)
40 : "+a" (count), "+a" (src), "=a" (tmp1), "=a" (tmp2)
41 : "d" (reg0) : "cc", "memory");
42 return count;
43}
44
45static size_t copy_in_kernel(size_t count, void __user *to,
46 const void __user *from)
47{
48 unsigned long tmp1;
49
50 asm volatile(
51 " "AHI" %0,-1\n"
52 " jo 5f\n"
53 " bras %3,3f\n"
54 "0:"AHI" %0,257\n"
55 "1: mvc 0(1,%1),0(%2)\n"
56 " la %1,1(%1)\n"
57 " la %2,1(%2)\n"
58 " "AHI" %0,-1\n"
59 " jnz 1b\n"
60 " j 5f\n"
61 "2: mvc 0(256,%1),0(%2)\n"
62 " la %1,256(%1)\n"
63 " la %2,256(%2)\n"
64 "3:"AHI" %0,-256\n"
65 " jnm 2b\n"
66 "4: ex %0,1b-0b(%3)\n"
67 "5:"SLR" %0,%0\n"
68 "6:\n"
69 EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
70 : "+a" (count), "+a" (to), "+a" (from), "=a" (tmp1)
71 : : "cc", "memory");
72 return count;
73}
17 74
18/* 75/*
19 * Returns kernel address for user virtual address. If the returned address is 76 * Returns kernel address for user virtual address. If the returned address is
@@ -123,10 +180,8 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
123{ 180{
124 size_t rc; 181 size_t rc;
125 182
126 if (segment_eq(get_fs(), KERNEL_DS)) { 183 if (segment_eq(get_fs(), KERNEL_DS))
127 memcpy(to, (void __kernel __force *) from, n); 184 return copy_in_kernel(n, (void __user *) to, from);
128 return 0;
129 }
130 rc = __user_copy_pt((unsigned long) from, to, n, 0); 185 rc = __user_copy_pt((unsigned long) from, to, n, 0);
131 if (unlikely(rc)) 186 if (unlikely(rc))
132 memset(to + n - rc, 0, rc); 187 memset(to + n - rc, 0, rc);
@@ -135,30 +190,28 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
135 190
136size_t copy_to_user_pt(size_t n, void __user *to, const void *from) 191size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
137{ 192{
138 if (segment_eq(get_fs(), KERNEL_DS)) { 193 if (segment_eq(get_fs(), KERNEL_DS))
139 memcpy((void __kernel __force *) to, from, n); 194 return copy_in_kernel(n, to, (void __user *) from);
140 return 0;
141 }
142 return __user_copy_pt((unsigned long) to, (void *) from, n, 1); 195 return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
143} 196}
144 197
145static size_t clear_user_pt(size_t n, void __user *to) 198static size_t clear_user_pt(size_t n, void __user *to)
146{ 199{
200 void *zpage = &empty_zero_page;
147 long done, size, ret; 201 long done, size, ret;
148 202
149 if (segment_eq(get_fs(), KERNEL_DS)) {
150 memset((void __kernel __force *) to, 0, n);
151 return 0;
152 }
153 done = 0; 203 done = 0;
154 do { 204 do {
155 if (n - done > PAGE_SIZE) 205 if (n - done > PAGE_SIZE)
156 size = PAGE_SIZE; 206 size = PAGE_SIZE;
157 else 207 else
158 size = n - done; 208 size = n - done;
159 ret = __user_copy_pt((unsigned long) to + done, 209 if (segment_eq(get_fs(), KERNEL_DS))
160 &empty_zero_page, size, 1); 210 ret = copy_in_kernel(n, to, (void __user *) zpage);
211 else
212 ret = __user_copy_pt((unsigned long) to, zpage, size, 1);
161 done += size; 213 done += size;
214 to += size;
162 if (ret) 215 if (ret)
163 return ret + n - done; 216 return ret + n - done;
164 } while (done < n); 217 } while (done < n);
@@ -172,8 +225,10 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
172 unsigned long offset, done, len, kaddr; 225 unsigned long offset, done, len, kaddr;
173 size_t len_str; 226 size_t len_str;
174 227
228 if (unlikely(!count))
229 return 0;
175 if (segment_eq(get_fs(), KERNEL_DS)) 230 if (segment_eq(get_fs(), KERNEL_DS))
176 return strnlen((const char __kernel __force *) src, count) + 1; 231 return strnlen_kernel(count, src);
177 done = 0; 232 done = 0;
178retry: 233retry:
179 spin_lock(&mm->page_table_lock); 234 spin_lock(&mm->page_table_lock);
@@ -200,25 +255,27 @@ fault:
200static size_t strncpy_from_user_pt(size_t count, const char __user *src, 255static size_t strncpy_from_user_pt(size_t count, const char __user *src,
201 char *dst) 256 char *dst)
202{ 257{
203 size_t n = strnlen_user_pt(count, src); 258 size_t done, len, offset, len_str;
204 259
205 if (!n) 260 if (unlikely(!count))
206 return -EFAULT; 261 return 0;
207 if (n > count) 262 done = 0;
208 n = count; 263 do {
209 if (segment_eq(get_fs(), KERNEL_DS)) { 264 offset = (size_t)src & ~PAGE_MASK;
210 memcpy(dst, (const char __kernel __force *) src, n); 265 len = min(count - done, PAGE_SIZE - offset);
211 if (dst[n-1] == '\0') 266 if (segment_eq(get_fs(), KERNEL_DS)) {
212 return n-1; 267 if (copy_in_kernel(len, (void __user *) dst, src))
213 else 268 return -EFAULT;
214 return n; 269 } else {
215 } 270 if (__user_copy_pt((unsigned long) src, dst, len, 0))
216 if (__user_copy_pt((unsigned long) src, dst, n, 0)) 271 return -EFAULT;
217 return -EFAULT; 272 }
218 if (dst[n-1] == '\0') 273 len_str = strnlen(dst, len);
219 return n-1; 274 done += len_str;
220 else 275 src += len_str;
221 return n; 276 dst += len_str;
277 } while ((len_str == len) && (done < count));
278 return done;
222} 279}
223 280
224static size_t copy_in_user_pt(size_t n, void __user *to, 281static size_t copy_in_user_pt(size_t n, void __user *to,
@@ -231,10 +288,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
231 unsigned long kaddr_to, kaddr_from; 288 unsigned long kaddr_to, kaddr_from;
232 int write_user; 289 int write_user;
233 290
234 if (segment_eq(get_fs(), KERNEL_DS)) { 291 if (segment_eq(get_fs(), KERNEL_DS))
235 memcpy((void __force *) to, (void __force *) from, n); 292 return copy_in_kernel(n, to, from);
236 return 0;
237 }
238 done = 0; 293 done = 0;
239retry: 294retry:
240 spin_lock(&mm->page_table_lock); 295 spin_lock(&mm->page_table_lock);
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 6fbd06338270..4a75d475b06a 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -188,6 +188,8 @@ size_t strnlen_user_std(size_t size, const char __user *src)
188 register unsigned long reg0 asm("0") = 0UL; 188 register unsigned long reg0 asm("0") = 0UL;
189 unsigned long tmp1, tmp2; 189 unsigned long tmp1, tmp2;
190 190
191 if (unlikely(!size))
192 return 0;
191 asm volatile( 193 asm volatile(
192 " la %2,0(%1)\n" 194 " la %2,0(%1)\n"
193 " la %3,0(%0,%1)\n" 195 " la %3,0(%0,%1)\n"
@@ -204,38 +206,24 @@ size_t strnlen_user_std(size_t size, const char __user *src)
204 return size; 206 return size;
205} 207}
206 208
207size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst) 209size_t strncpy_from_user_std(size_t count, const char __user *src, char *dst)
208{ 210{
209 register unsigned long reg0 asm("0") = 0UL; 211 size_t done, len, offset, len_str;
210 unsigned long tmp1, tmp2;
211 212
212 asm volatile( 213 if (unlikely(!count))
213 " la %3,0(%1)\n" 214 return 0;
214 " la %4,0(%0,%1)\n" 215 done = 0;
215 " sacf 256\n" 216 do {
216 "0: srst %4,%3\n" 217 offset = (size_t)src & ~PAGE_MASK;
217 " jo 0b\n" 218 len = min(count - done, PAGE_SIZE - offset);
218 " sacf 0\n" 219 if (copy_from_user_std(len, src, dst))
219 " la %0,0(%4)\n" 220 return -EFAULT;
220 " jh 1f\n" /* found \0 in string ? */ 221 len_str = strnlen(dst, len);
221 " "AHI" %4,1\n" /* include \0 in copy */ 222 done += len_str;
222 "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */ 223 src += len_str;
223 " "SLR" %4,%1\n" /* %4 = copy length (including \0) */ 224 dst += len_str;
224 "2: mvcp 0(%4,%2),0(%1),%5\n" 225 } while ((len_str == len) && (done < count));
225 " jz 9f\n" 226 return done;
226 "3:"AHI" %4,-256\n"
227 " la %1,256(%1)\n"
228 " la %2,256(%2)\n"
229 "4: mvcp 0(%4,%2),0(%1),%5\n"
230 " jnz 3b\n"
231 " j 9f\n"
232 "7: sacf 0\n"
233 "8:"LHI" %0,%6\n"
234 "9:\n"
235 EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b)
236 : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2)
237 : "d" (reg0), "K" (-EFAULT) : "cc", "memory");
238 return size;
239} 227}
240 228
241#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ 229#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \