aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-09-22 15:50:35 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-22 15:50:35 -0400
commita489d159229fcc07bbb7566ac4fac745b79197ad (patch)
treeea7bcf20e845de8a96ccc1549799ac073fb28a84 /arch/s390/lib
parenta48178a2fa17beee17d7e6aeaa6ed2db5813552d (diff)
parent388c571cffc4ae4e64f0786333e811308acbbc10 (diff)
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: (44 commits) [S390] hypfs crashes with invalid mount option. [S390] cio: subchannel evaluation function operates without lock [S390] cio: always query all paths on path verification. [S390] cio: update path groups on logical CHPID changes. [S390] cio: subchannels in no-path state. [S390] Replace nopav-message on VM. [S390] set modalias for ccw bus uevents. [S390] Get rid of DBG macro. [S390] Use alternative user-copy operations for new hardware. [S390] Make user-copy operations run-time configurable. [S390] Cleanup in signal handling code. [S390] Cleanup in page table related code. [S390] Linux API for writing z/VM APPLDATA Monitor records. [S390] xpram off by one error. [S390] Remove kexec experimental flag. [S390] cleanup appldata. [S390] fix typo in vmcp. [S390] Kernel stack overflow handling. [S390] qdio slsb processing state. [S390] Missing initialization in common i/o layer. ...
Diffstat (limited to 'arch/s390/lib')
-rw-r--r--arch/s390/lib/Makefile4
-rw-r--r--arch/s390/lib/uaccess.S211
-rw-r--r--arch/s390/lib/uaccess64.S207
-rw-r--r--arch/s390/lib/uaccess_mvcos.c156
-rw-r--r--arch/s390/lib/uaccess_std.c340
5 files changed, 498 insertions, 420 deletions
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index e05d087a6eae..c42ffedfdb49 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -4,6 +4,6 @@
4 4
5EXTRA_AFLAGS := -traditional 5EXTRA_AFLAGS := -traditional
6 6
7lib-y += delay.o string.o 7lib-y += delay.o string.o uaccess_std.o
8lib-y += $(if $(CONFIG_64BIT),uaccess64.o,uaccess.o) 8lib-$(CONFIG_64BIT) += uaccess_mvcos.o
9lib-$(CONFIG_SMP) += spinlock.o 9lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
deleted file mode 100644
index 837275284d9f..000000000000
--- a/arch/s390/lib/uaccess.S
+++ /dev/null
@@ -1,211 +0,0 @@
1/*
2 * arch/s390/lib/uaccess.S
3 * __copy_{from|to}_user functions.
4 *
5 * s390
6 * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * These functions have standard call interface
10 */
11
12#include <linux/errno.h>
13#include <asm/lowcore.h>
14#include <asm/asm-offsets.h>
15
16 .text
17 .align 4
18 .globl __copy_from_user_asm
19 # %r2 = to, %r3 = n, %r4 = from
20__copy_from_user_asm:
21 slr %r0,%r0
220: mvcp 0(%r3,%r2),0(%r4),%r0
23 jnz 1f
24 slr %r2,%r2
25 br %r14
261: la %r2,256(%r2)
27 la %r4,256(%r4)
28 ahi %r3,-256
292: mvcp 0(%r3,%r2),0(%r4),%r0
30 jnz 1b
313: slr %r2,%r2
32 br %r14
334: lhi %r0,-4096
34 lr %r5,%r4
35 slr %r5,%r0
36 nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
37 slr %r5,%r4 # %r5 = #bytes to next user page boundary
38 clr %r3,%r5 # copy crosses next page boundary ?
39 jnh 6f # no, the current page faulted
40 # move with the reduced length which is < 256
415: mvcp 0(%r5,%r2),0(%r4),%r0
42 slr %r3,%r5
436: lr %r2,%r3
44 br %r14
45 .section __ex_table,"a"
46 .long 0b,4b
47 .long 2b,4b
48 .long 5b,6b
49 .previous
50
51 .align 4
52 .text
53 .globl __copy_to_user_asm
54 # %r2 = from, %r3 = n, %r4 = to
55__copy_to_user_asm:
56 slr %r0,%r0
570: mvcs 0(%r3,%r4),0(%r2),%r0
58 jnz 1f
59 slr %r2,%r2
60 br %r14
611: la %r2,256(%r2)
62 la %r4,256(%r4)
63 ahi %r3,-256
642: mvcs 0(%r3,%r4),0(%r2),%r0
65 jnz 1b
663: slr %r2,%r2
67 br %r14
684: lhi %r0,-4096
69 lr %r5,%r4
70 slr %r5,%r0
71 nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
72 slr %r5,%r4 # %r5 = #bytes to next user page boundary
73 clr %r3,%r5 # copy crosses next page boundary ?
74 jnh 6f # no, the current page faulted
75 # move with the reduced length which is < 256
765: mvcs 0(%r5,%r4),0(%r2),%r0
77 slr %r3,%r5
786: lr %r2,%r3
79 br %r14
80 .section __ex_table,"a"
81 .long 0b,4b
82 .long 2b,4b
83 .long 5b,6b
84 .previous
85
86 .align 4
87 .text
88 .globl __copy_in_user_asm
89 # %r2 = from, %r3 = n, %r4 = to
90__copy_in_user_asm:
91 ahi %r3,-1
92 jo 6f
93 sacf 256
94 bras %r1,4f
950: ahi %r3,257
961: mvc 0(1,%r4),0(%r2)
97 la %r2,1(%r2)
98 la %r4,1(%r4)
99 ahi %r3,-1
100 jnz 1b
1012: lr %r2,%r3
102 br %r14
1033: mvc 0(256,%r4),0(%r2)
104 la %r2,256(%r2)
105 la %r4,256(%r4)
1064: ahi %r3,-256
107 jnm 3b
1085: ex %r3,4(%r1)
109 sacf 0
1106: slr %r2,%r2
111 br %r14
112 .section __ex_table,"a"
113 .long 1b,2b
114 .long 3b,0b
115 .long 5b,0b
116 .previous
117
118 .align 4
119 .text
120 .globl __clear_user_asm
121 # %r2 = to, %r3 = n
122__clear_user_asm:
123 bras %r5,0f
124 .long empty_zero_page
1250: l %r5,0(%r5)
126 slr %r0,%r0
1271: mvcs 0(%r3,%r2),0(%r5),%r0
128 jnz 2f
129 slr %r2,%r2
130 br %r14
1312: la %r2,256(%r2)
132 ahi %r3,-256
1333: mvcs 0(%r3,%r2),0(%r5),%r0
134 jnz 2b
1354: slr %r2,%r2
136 br %r14
1375: lhi %r0,-4096
138 lr %r4,%r2
139 slr %r4,%r0
140 nr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
141 slr %r4,%r2 # %r4 = #bytes to next user page boundary
142 clr %r3,%r4 # clear crosses next page boundary ?
143 jnh 7f # no, the current page faulted
144 # clear with the reduced length which is < 256
1456: mvcs 0(%r4,%r2),0(%r5),%r0
146 slr %r3,%r4
1477: lr %r2,%r3
148 br %r14
149 .section __ex_table,"a"
150 .long 1b,5b
151 .long 3b,5b
152 .long 6b,7b
153 .previous
154
155 .align 4
156 .text
157 .globl __strncpy_from_user_asm
158 # %r2 = count, %r3 = dst, %r4 = src
159__strncpy_from_user_asm:
160 lhi %r0,0
161 lr %r1,%r4
162 la %r4,0(%r4) # clear high order bit from %r4
163 la %r2,0(%r2,%r4) # %r2 points to first byte after string
164 sacf 256
1650: srst %r2,%r1
166 jo 0b
167 sacf 0
168 lr %r1,%r2
169 jh 1f # \0 found in string ?
170 ahi %r1,1 # include \0 in copy
1711: slr %r1,%r4 # %r1 = copy length (without \0)
172 slr %r2,%r4 # %r2 = return length (including \0)
1732: mvcp 0(%r1,%r3),0(%r4),%r0
174 jnz 3f
175 br %r14
1763: la %r3,256(%r3)
177 la %r4,256(%r4)
178 ahi %r1,-256
179 mvcp 0(%r1,%r3),0(%r4),%r0
180 jnz 3b
181 br %r14
1824: sacf 0
183 lhi %r2,-EFAULT
184 br %r14
185 .section __ex_table,"a"
186 .long 0b,4b
187 .previous
188
189 .align 4
190 .text
191 .globl __strnlen_user_asm
192 # %r2 = count, %r3 = src
193__strnlen_user_asm:
194 lhi %r0,0
195 lr %r1,%r3
196 la %r3,0(%r3) # clear high order bit from %r4
197 la %r2,0(%r2,%r3) # %r2 points to first byte after string
198 sacf 256
1990: srst %r2,%r1
200 jo 0b
201 sacf 0
202 ahi %r2,1 # strnlen_user result includes the \0
203 # or return count+1 if \0 not found
204 slr %r2,%r3
205 br %r14
2062: sacf 0
207 slr %r2,%r2 # return 0 on exception
208 br %r14
209 .section __ex_table,"a"
210 .long 0b,2b
211 .previous
diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S
deleted file mode 100644
index 1f755be22f92..000000000000
--- a/arch/s390/lib/uaccess64.S
+++ /dev/null
@@ -1,207 +0,0 @@
1/*
2 * arch/s390x/lib/uaccess.S
3 * __copy_{from|to}_user functions.
4 *
5 * s390
6 * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * These functions have standard call interface
10 */
11
12#include <linux/errno.h>
13#include <asm/lowcore.h>
14#include <asm/asm-offsets.h>
15
16 .text
17 .align 4
18 .globl __copy_from_user_asm
19 # %r2 = to, %r3 = n, %r4 = from
20__copy_from_user_asm:
21 slgr %r0,%r0
220: mvcp 0(%r3,%r2),0(%r4),%r0
23 jnz 1f
24 slgr %r2,%r2
25 br %r14
261: la %r2,256(%r2)
27 la %r4,256(%r4)
28 aghi %r3,-256
292: mvcp 0(%r3,%r2),0(%r4),%r0
30 jnz 1b
313: slgr %r2,%r2
32 br %r14
334: lghi %r0,-4096
34 lgr %r5,%r4
35 slgr %r5,%r0
36 ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
37 slgr %r5,%r4 # %r5 = #bytes to next user page boundary
38 clgr %r3,%r5 # copy crosses next page boundary ?
39 jnh 6f # no, the current page faulted
40 # move with the reduced length which is < 256
415: mvcp 0(%r5,%r2),0(%r4),%r0
42 slgr %r3,%r5
436: lgr %r2,%r3
44 br %r14
45 .section __ex_table,"a"
46 .quad 0b,4b
47 .quad 2b,4b
48 .quad 5b,6b
49 .previous
50
51 .align 4
52 .text
53 .globl __copy_to_user_asm
54 # %r2 = from, %r3 = n, %r4 = to
55__copy_to_user_asm:
56 slgr %r0,%r0
570: mvcs 0(%r3,%r4),0(%r2),%r0
58 jnz 1f
59 slgr %r2,%r2
60 br %r14
611: la %r2,256(%r2)
62 la %r4,256(%r4)
63 aghi %r3,-256
642: mvcs 0(%r3,%r4),0(%r2),%r0
65 jnz 1b
663: slgr %r2,%r2
67 br %r14
684: lghi %r0,-4096
69 lgr %r5,%r4
70 slgr %r5,%r0
71 ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
72 slgr %r5,%r4 # %r5 = #bytes to next user page boundary
73 clgr %r3,%r5 # copy crosses next page boundary ?
74 jnh 6f # no, the current page faulted
75 # move with the reduced length which is < 256
765: mvcs 0(%r5,%r4),0(%r2),%r0
77 slgr %r3,%r5
786: lgr %r2,%r3
79 br %r14
80 .section __ex_table,"a"
81 .quad 0b,4b
82 .quad 2b,4b
83 .quad 5b,6b
84 .previous
85
86 .align 4
87 .text
88 .globl __copy_in_user_asm
89 # %r2 = from, %r3 = n, %r4 = to
90__copy_in_user_asm:
91 aghi %r3,-1
92 jo 6f
93 sacf 256
94 bras %r1,4f
950: aghi %r3,257
961: mvc 0(1,%r4),0(%r2)
97 la %r2,1(%r2)
98 la %r4,1(%r4)
99 aghi %r3,-1
100 jnz 1b
1012: lgr %r2,%r3
102 br %r14
1033: mvc 0(256,%r4),0(%r2)
104 la %r2,256(%r2)
105 la %r4,256(%r4)
1064: aghi %r3,-256
107 jnm 3b
1085: ex %r3,4(%r1)
109 sacf 0
1106: slgr %r2,%r2
111 br 14
112 .section __ex_table,"a"
113 .quad 1b,2b
114 .quad 3b,0b
115 .quad 5b,0b
116 .previous
117
118 .align 4
119 .text
120 .globl __clear_user_asm
121 # %r2 = to, %r3 = n
122__clear_user_asm:
123 slgr %r0,%r0
124 larl %r5,empty_zero_page
1251: mvcs 0(%r3,%r2),0(%r5),%r0
126 jnz 2f
127 slgr %r2,%r2
128 br %r14
1292: la %r2,256(%r2)
130 aghi %r3,-256
1313: mvcs 0(%r3,%r2),0(%r5),%r0
132 jnz 2b
1334: slgr %r2,%r2
134 br %r14
1355: lghi %r0,-4096
136 lgr %r4,%r2
137 slgr %r4,%r0
138 ngr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
139 slgr %r4,%r2 # %r4 = #bytes to next user page boundary
140 clgr %r3,%r4 # clear crosses next page boundary ?
141 jnh 7f # no, the current page faulted
142 # clear with the reduced length which is < 256
1436: mvcs 0(%r4,%r2),0(%r5),%r0
144 slgr %r3,%r4
1457: lgr %r2,%r3
146 br %r14
147 .section __ex_table,"a"
148 .quad 1b,5b
149 .quad 3b,5b
150 .quad 6b,7b
151 .previous
152
153 .align 4
154 .text
155 .globl __strncpy_from_user_asm
156 # %r2 = count, %r3 = dst, %r4 = src
157__strncpy_from_user_asm:
158 lghi %r0,0
159 lgr %r1,%r4
160 la %r2,0(%r2,%r4) # %r2 points to first byte after string
161 sacf 256
1620: srst %r2,%r1
163 jo 0b
164 sacf 0
165 lgr %r1,%r2
166 jh 1f # \0 found in string ?
167 aghi %r1,1 # include \0 in copy
1681: slgr %r1,%r4 # %r1 = copy length (without \0)
169 slgr %r2,%r4 # %r2 = return length (including \0)
1702: mvcp 0(%r1,%r3),0(%r4),%r0
171 jnz 3f
172 br %r14
1733: la %r3,256(%r3)
174 la %r4,256(%r4)
175 aghi %r1,-256
176 mvcp 0(%r1,%r3),0(%r4),%r0
177 jnz 3b
178 br %r14
1794: sacf 0
180 lghi %r2,-EFAULT
181 br %r14
182 .section __ex_table,"a"
183 .quad 0b,4b
184 .previous
185
186 .align 4
187 .text
188 .globl __strnlen_user_asm
189 # %r2 = count, %r3 = src
190__strnlen_user_asm:
191 lghi %r0,0
192 lgr %r1,%r3
193 la %r2,0(%r2,%r3) # %r2 points to first byte after string
194 sacf 256
1950: srst %r2,%r1
196 jo 0b
197 sacf 0
198 aghi %r2,1 # strnlen_user result includes the \0
199 # or return count+1 if \0 not found
200 slgr %r2,%r3
201 br %r14
2022: sacf 0
203 slgr %r2,%r2 # return 0 on exception
204 br %r14
205 .section __ex_table,"a"
206 .quad 0b,2b
207 .previous
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
new file mode 100644
index 000000000000..86c96d6c191a
--- /dev/null
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -0,0 +1,156 @@
1/*
2 * arch/s390/lib/uaccess_mvcos.c
3 *
4 * Optimized user space space access functions based on mvcos.
5 *
6 * Copyright (C) IBM Corp. 2006
7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
8 * Gerald Schaefer (gerald.schaefer@de.ibm.com)
9 */
10
11#include <linux/errno.h>
12#include <linux/mm.h>
13#include <asm/uaccess.h>
14#include <asm/futex.h>
15
16#ifndef __s390x__
17#define AHI "ahi"
18#define ALR "alr"
19#define CLR "clr"
20#define LHI "lhi"
21#define SLR "slr"
22#else
23#define AHI "aghi"
24#define ALR "algr"
25#define CLR "clgr"
26#define LHI "lghi"
27#define SLR "slgr"
28#endif
29
30size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
31{
32 register unsigned long reg0 asm("0") = 0x81UL;
33 unsigned long tmp1, tmp2;
34
35 tmp1 = -4096UL;
36 asm volatile(
37 "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
38 " jz 4f\n"
39 "1:"ALR" %0,%3\n"
40 " "SLR" %1,%3\n"
41 " "SLR" %2,%3\n"
42 " j 0b\n"
43 "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
44 " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
45 " "SLR" %4,%1\n"
46 " "CLR" %0,%4\n" /* copy crosses next page boundary? */
47 " jnh 5f\n"
48 "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
49 " "SLR" %0,%4\n"
50 " j 5f\n"
51 "4:"SLR" %0,%0\n"
52 "5: \n"
53 EX_TABLE(0b,2b) EX_TABLE(3b,5b)
54 : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
55 : "d" (reg0) : "cc", "memory");
56 return size;
57}
58
59size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
60{
61 register unsigned long reg0 asm("0") = 0x810000UL;
62 unsigned long tmp1, tmp2;
63
64 tmp1 = -4096UL;
65 asm volatile(
66 "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
67 " jz 4f\n"
68 "1:"ALR" %0,%3\n"
69 " "SLR" %1,%3\n"
70 " "SLR" %2,%3\n"
71 " j 0b\n"
72 "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
73 " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
74 " "SLR" %4,%1\n"
75 " "CLR" %0,%4\n" /* copy crosses next page boundary? */
76 " jnh 5f\n"
77 "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
78 " "SLR" %0,%4\n"
79 " j 5f\n"
80 "4:"SLR" %0,%0\n"
81 "5: \n"
82 EX_TABLE(0b,2b) EX_TABLE(3b,5b)
83 : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
84 : "d" (reg0) : "cc", "memory");
85 return size;
86}
87
88size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
89{
90 register unsigned long reg0 asm("0") = 0x810081UL;
91 unsigned long tmp1, tmp2;
92
93 tmp1 = -4096UL;
94 /* FIXME: copy with reduced length. */
95 asm volatile(
96 "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
97 " jz 2f\n"
98 "1:"ALR" %0,%3\n"
99 " "SLR" %1,%3\n"
100 " "SLR" %2,%3\n"
101 " j 0b\n"
102 "2:"SLR" %0,%0\n"
103 "3: \n"
104 EX_TABLE(0b,3b)
105 : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
106 : "d" (reg0) : "cc", "memory");
107 return size;
108}
109
110size_t clear_user_mvcos(size_t size, void __user *to)
111{
112 register unsigned long reg0 asm("0") = 0x810000UL;
113 unsigned long tmp1, tmp2;
114
115 tmp1 = -4096UL;
116 asm volatile(
117 "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
118 " jz 4f\n"
119 "1:"ALR" %0,%2\n"
120 " "SLR" %1,%2\n"
121 " j 0b\n"
122 "2: la %3,4095(%1)\n"/* %4 = to + 4095 */
123 " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */
124 " "SLR" %3,%1\n"
125 " "CLR" %0,%3\n" /* copy crosses next page boundary? */
126 " jnh 5f\n"
127 "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
128 " "SLR" %0,%3\n"
129 " j 5f\n"
130 "4:"SLR" %0,%0\n"
131 "5: \n"
132 EX_TABLE(0b,2b) EX_TABLE(3b,5b)
133 : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
134 : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
135 return size;
136}
137
138extern size_t copy_from_user_std_small(size_t, const void __user *, void *);
139extern size_t copy_to_user_std_small(size_t, void __user *, const void *);
140extern size_t strnlen_user_std(size_t, const char __user *);
141extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
142extern int futex_atomic_op(int, int __user *, int, int *);
143extern int futex_atomic_cmpxchg(int __user *, int, int);
144
145struct uaccess_ops uaccess_mvcos = {
146 .copy_from_user = copy_from_user_mvcos,
147 .copy_from_user_small = copy_from_user_std_small,
148 .copy_to_user = copy_to_user_mvcos,
149 .copy_to_user_small = copy_to_user_std_small,
150 .copy_in_user = copy_in_user_mvcos,
151 .clear_user = clear_user_mvcos,
152 .strnlen_user = strnlen_user_std,
153 .strncpy_from_user = strncpy_from_user_std,
154 .futex_atomic_op = futex_atomic_op,
155 .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
156};
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
new file mode 100644
index 000000000000..9a4d4a29ea79
--- /dev/null
+++ b/arch/s390/lib/uaccess_std.c
@@ -0,0 +1,340 @@
1/*
2 * arch/s390/lib/uaccess_std.c
3 *
4 * Standard user space access functions based on mvcp/mvcs and doing
5 * interesting things in the secondary space mode.
6 *
7 * Copyright (C) IBM Corp. 2006
8 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
9 * Gerald Schaefer (gerald.schaefer@de.ibm.com)
10 */
11
12#include <linux/errno.h>
13#include <linux/mm.h>
14#include <asm/uaccess.h>
15#include <asm/futex.h>
16
17#ifndef __s390x__
18#define AHI "ahi"
19#define ALR "alr"
20#define CLR "clr"
21#define LHI "lhi"
22#define SLR "slr"
23#else
24#define AHI "aghi"
25#define ALR "algr"
26#define CLR "clgr"
27#define LHI "lghi"
28#define SLR "slgr"
29#endif
30
31size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
32{
33 unsigned long tmp1, tmp2;
34
35 tmp1 = -256UL;
36 asm volatile(
37 "0: mvcp 0(%0,%2),0(%1),%3\n"
38 " jz 5f\n"
39 "1:"ALR" %0,%3\n"
40 " la %1,256(%1)\n"
41 " la %2,256(%2)\n"
42 "2: mvcp 0(%0,%2),0(%1),%3\n"
43 " jnz 1b\n"
44 " j 5f\n"
45 "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
46 " "LHI" %3,-4096\n"
47 " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
48 " "SLR" %4,%1\n"
49 " "CLR" %0,%4\n" /* copy crosses next page boundary? */
50 " jnh 6f\n"
51 "4: mvcp 0(%4,%2),0(%1),%3\n"
52 " "SLR" %0,%4\n"
53 " j 6f\n"
54 "5:"SLR" %0,%0\n"
55 "6: \n"
56 EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
57 : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
58 : : "cc", "memory");
59 return size;
60}
61
62size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x)
63{
64 unsigned long tmp1, tmp2;
65
66 tmp1 = 0UL;
67 asm volatile(
68 "0: mvcp 0(%0,%2),0(%1),%3\n"
69 " "SLR" %0,%0\n"
70 " j 3f\n"
71 "1: la %4,255(%1)\n" /* %4 = ptr + 255 */
72 " "LHI" %3,-4096\n"
73 " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
74 " "SLR" %4,%1\n"
75 " "CLR" %0,%4\n" /* copy crosses next page boundary? */
76 " jnh 3f\n"
77 "2: mvcp 0(%4,%2),0(%1),%3\n"
78 " "SLR" %0,%4\n"
79 "3:\n"
80 EX_TABLE(0b,1b) EX_TABLE(2b,3b)
81 : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
82 : : "cc", "memory");
83 return size;
84}
85
86size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
87{
88 unsigned long tmp1, tmp2;
89
90 tmp1 = -256UL;
91 asm volatile(
92 "0: mvcs 0(%0,%1),0(%2),%3\n"
93 " jz 5f\n"
94 "1:"ALR" %0,%3\n"
95 " la %1,256(%1)\n"
96 " la %2,256(%2)\n"
97 "2: mvcs 0(%0,%1),0(%2),%3\n"
98 " jnz 1b\n"
99 " j 5f\n"
100 "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
101 " "LHI" %3,-4096\n"
102 " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
103 " "SLR" %4,%1\n"
104 " "CLR" %0,%4\n" /* copy crosses next page boundary? */
105 " jnh 6f\n"
106 "4: mvcs 0(%4,%1),0(%2),%3\n"
107 " "SLR" %0,%4\n"
108 " j 6f\n"
109 "5:"SLR" %0,%0\n"
110 "6: \n"
111 EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
112 : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
113 : : "cc", "memory");
114 return size;
115}
116
117size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x)
118{
119 unsigned long tmp1, tmp2;
120
121 tmp1 = 0UL;
122 asm volatile(
123 "0: mvcs 0(%0,%1),0(%2),%3\n"
124 " "SLR" %0,%0\n"
125 " j 3f\n"
126 "1: la %4,255(%1)\n" /* ptr + 255 */
127 " "LHI" %3,-4096\n"
128 " nr %4,%3\n" /* (ptr + 255) & -4096UL */
129 " "SLR" %4,%1\n"
130 " "CLR" %0,%4\n" /* copy crosses next page boundary? */
131 " jnh 3f\n"
132 "2: mvcs 0(%4,%1),0(%2),%3\n"
133 " "SLR" %0,%4\n"
134 "3:\n"
135 EX_TABLE(0b,1b) EX_TABLE(2b,3b)
136 : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
137 : : "cc", "memory");
138 return size;
139}
140
141size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
142{
143 unsigned long tmp1;
144
145 asm volatile(
146 " "AHI" %0,-1\n"
147 " jo 5f\n"
148 " sacf 256\n"
149 " bras %3,3f\n"
150 "0:"AHI" %0,257\n"
151 "1: mvc 0(1,%1),0(%2)\n"
152 " la %1,1(%1)\n"
153 " la %2,1(%2)\n"
154 " "AHI" %0,-1\n"
155 " jnz 1b\n"
156 " j 5f\n"
157 "2: mvc 0(256,%1),0(%2)\n"
158 " la %1,256(%1)\n"
159 " la %2,256(%2)\n"
160 "3:"AHI" %0,-256\n"
161 " jnm 2b\n"
162 "4: ex %0,1b-0b(%3)\n"
163 " sacf 0\n"
164 "5: "SLR" %0,%0\n"
165 "6:\n"
166 EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
167 : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
168 : : "cc", "memory");
169 return size;
170}
171
172size_t clear_user_std(size_t size, void __user *to)
173{
174 unsigned long tmp1, tmp2;
175
176 asm volatile(
177 " "AHI" %0,-1\n"
178 " jo 5f\n"
179 " sacf 256\n"
180 " bras %3,3f\n"
181 " xc 0(1,%1),0(%1)\n"
182 "0:"AHI" %0,257\n"
183 " la %2,255(%1)\n" /* %2 = ptr + 255 */
184 " srl %2,12\n"
185 " sll %2,12\n" /* %2 = (ptr + 255) & -4096 */
186 " "SLR" %2,%1\n"
187 " "CLR" %0,%2\n" /* clear crosses next page boundary? */
188 " jnh 5f\n"
189 " "AHI" %2,-1\n"
190 "1: ex %2,0(%3)\n"
191 " "AHI" %2,1\n"
192 " "SLR" %0,%2\n"
193 " j 5f\n"
194 "2: xc 0(256,%1),0(%1)\n"
195 " la %1,256(%1)\n"
196 "3:"AHI" %0,-256\n"
197 " jnm 2b\n"
198 "4: ex %0,0(%3)\n"
199 " sacf 0\n"
200 "5: "SLR" %0,%0\n"
201 "6:\n"
202 EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
203 : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
204 : : "cc", "memory");
205 return size;
206}
207
208size_t strnlen_user_std(size_t size, const char __user *src)
209{
210 register unsigned long reg0 asm("0") = 0UL;
211 unsigned long tmp1, tmp2;
212
213 asm volatile(
214 " la %2,0(%1)\n"
215 " la %3,0(%0,%1)\n"
216 " "SLR" %0,%0\n"
217 " sacf 256\n"
218 "0: srst %3,%2\n"
219 " jo 0b\n"
220 " la %0,1(%3)\n" /* strnlen_user results includes \0 */
221 " "SLR" %0,%1\n"
222 "1: sacf 0\n"
223 EX_TABLE(0b,1b)
224 : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2)
225 : "d" (reg0) : "cc", "memory");
226 return size;
227}
228
229size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
230{
231 register unsigned long reg0 asm("0") = 0UL;
232 unsigned long tmp1, tmp2;
233
234 asm volatile(
235 " la %3,0(%1)\n"
236 " la %4,0(%0,%1)\n"
237 " sacf 256\n"
238 "0: srst %4,%3\n"
239 " jo 0b\n"
240 " sacf 0\n"
241 " la %0,0(%4)\n"
242 " jh 1f\n" /* found \0 in string ? */
243 " "AHI" %4,1\n" /* include \0 in copy */
244 "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */
245 " "SLR" %4,%1\n" /* %4 = copy length (including \0) */
246 "2: mvcp 0(%4,%2),0(%1),%5\n"
247 " jz 9f\n"
248 "3:"AHI" %4,-256\n"
249 " la %1,256(%1)\n"
250 " la %2,256(%2)\n"
251 "4: mvcp 0(%4,%2),0(%1),%5\n"
252 " jnz 3b\n"
253 " j 9f\n"
254 "7: sacf 0\n"
255 "8:"LHI" %0,%6\n"
256 "9:\n"
257 EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b)
258 : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2)
259 : "d" (reg0), "K" (-EFAULT) : "cc", "memory");
260 return size;
261}
262
263#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
264 asm volatile( \
265 " sacf 256\n" \
266 "0: l %1,0(%6)\n" \
267 "1:"insn \
268 "2: cs %1,%2,0(%6)\n" \
269 "3: jl 1b\n" \
270 " lhi %0,0\n" \
271 "4: sacf 0\n" \
272 EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
273 : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
274 "=m" (*uaddr) \
275 : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
276 "m" (*uaddr) : "cc");
277
278int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
279{
280 int oldval = 0, newval, ret;
281
282 inc_preempt_count();
283
284 switch (op) {
285 case FUTEX_OP_SET:
286 __futex_atomic_op("lr %2,%5\n",
287 ret, oldval, newval, uaddr, oparg);
288 break;
289 case FUTEX_OP_ADD:
290 __futex_atomic_op("lr %2,%1\nar %2,%5\n",
291 ret, oldval, newval, uaddr, oparg);
292 break;
293 case FUTEX_OP_OR:
294 __futex_atomic_op("lr %2,%1\nor %2,%5\n",
295 ret, oldval, newval, uaddr, oparg);
296 break;
297 case FUTEX_OP_ANDN:
298 __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
299 ret, oldval, newval, uaddr, oparg);
300 break;
301 case FUTEX_OP_XOR:
302 __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
303 ret, oldval, newval, uaddr, oparg);
304 break;
305 default:
306 ret = -ENOSYS;
307 }
308 dec_preempt_count();
309 *old = oldval;
310 return ret;
311}
312
313int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
314{
315 int ret;
316
317 asm volatile(
318 " sacf 256\n"
319 " cs %1,%4,0(%5)\n"
320 "0: lr %0,%1\n"
321 "1: sacf 0\n"
322 EX_TABLE(0b,1b)
323 : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
324 : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
325 : "cc", "memory" );
326 return ret;
327}
328
329struct uaccess_ops uaccess_std = {
330 .copy_from_user = copy_from_user_std,
331 .copy_from_user_small = copy_from_user_std_small,
332 .copy_to_user = copy_to_user_std,
333 .copy_to_user_small = copy_to_user_std_small,
334 .copy_in_user = copy_in_user_std,
335 .clear_user = clear_user_std,
336 .strnlen_user = strnlen_user_std,
337 .strncpy_from_user = strncpy_from_user_std,
338 .futex_atomic_op = futex_atomic_op,
339 .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
340};