xref: /openbmc/linux/arch/s390/lib/uaccess.c (revision 49d6e68f)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2457f2180SHeiko Carstens /*
3457f2180SHeiko Carstens  *  Standard user space access functions based on mvcp/mvcs and doing
4457f2180SHeiko Carstens  *  interesting things in the secondary space mode.
5457f2180SHeiko Carstens  *
6457f2180SHeiko Carstens  *    Copyright IBM Corp. 2006,2014
7457f2180SHeiko Carstens  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
8457f2180SHeiko Carstens  *		 Gerald Schaefer (gerald.schaefer@de.ibm.com)
9457f2180SHeiko Carstens  */
10457f2180SHeiko Carstens 
11457f2180SHeiko Carstens #include <linux/uaccess.h>
12457f2180SHeiko Carstens #include <linux/export.h>
13457f2180SHeiko Carstens #include <linux/mm.h>
14d09a307fSHeiko Carstens #include <asm/asm-extable.h>
15457f2180SHeiko Carstens 
1656e62a73SSven Schnelle #ifdef CONFIG_DEBUG_ENTRY
debug_user_asce(int exit)1756e62a73SSven Schnelle void debug_user_asce(int exit)
18062e5279SHeiko Carstens {
19062e5279SHeiko Carstens 	unsigned long cr1, cr7;
20062e5279SHeiko Carstens 
21062e5279SHeiko Carstens 	__ctl_store(cr1, 1, 1);
22062e5279SHeiko Carstens 	__ctl_store(cr7, 7, 7);
23062e5279SHeiko Carstens 	if (cr1 == S390_lowcore.kernel_asce && cr7 == S390_lowcore.user_asce)
24062e5279SHeiko Carstens 		return;
2556e62a73SSven Schnelle 	panic("incorrect ASCE on kernel %s\n"
26062e5279SHeiko Carstens 	      "cr1:    %016lx cr7:  %016lx\n"
27062e5279SHeiko Carstens 	      "kernel: %016llx user: %016llx\n",
2856e62a73SSven Schnelle 	      exit ? "exit" : "entry", cr1, cr7,
2956e62a73SSven Schnelle 	      S390_lowcore.kernel_asce, S390_lowcore.user_asce);
30062e5279SHeiko Carstens }
3156e62a73SSven Schnelle #endif /*CONFIG_DEBUG_ENTRY */
32062e5279SHeiko Carstens 
raw_copy_from_user_key(void * to,const void __user * from,unsigned long size,unsigned long key)334efd417fSVasily Gorbik static unsigned long raw_copy_from_user_key(void *to, const void __user *from,
34432b1cc7SJanis Schoetterl-Glausch 					    unsigned long size, unsigned long key)
35457f2180SHeiko Carstens {
36*c3bd8343SHeiko Carstens 	unsigned long rem;
37012a224eSNico Boehr 	union oac spec = {
38432b1cc7SJanis Schoetterl-Glausch 		.oac2.key = key,
39012a224eSNico Boehr 		.oac2.as = PSW_BITS_AS_SECONDARY,
40432b1cc7SJanis Schoetterl-Glausch 		.oac2.k = 1,
41012a224eSNico Boehr 		.oac2.a = 1,
42012a224eSNico Boehr 	};
43457f2180SHeiko Carstens 
44457f2180SHeiko Carstens 	asm volatile(
45012a224eSNico Boehr 		"	lr	0,%[spec]\n"
4610679e4dSHeiko Carstens 		"0:	mvcos	0(%[to]),0(%[from]),%[size]\n"
474e0b0ad4SHeiko Carstens 		"1:	jz	5f\n"
487f65d183SHeiko Carstens 		"	algr	%[size],%[val]\n"
497f65d183SHeiko Carstens 		"	slgr	%[from],%[val]\n"
507f65d183SHeiko Carstens 		"	slgr	%[to],%[val]\n"
51457f2180SHeiko Carstens 		"	j	0b\n"
527f65d183SHeiko Carstens 		"2:	la	%[rem],4095(%[from])\n"	/* rem = from + 4095 */
537f65d183SHeiko Carstens 		"	nr	%[rem],%[val]\n"	/* rem = (from + 4095) & -4096 */
547f65d183SHeiko Carstens 		"	slgr	%[rem],%[from]\n"
557f65d183SHeiko Carstens 		"	clgr	%[size],%[rem]\n"	/* copy crosses next page boundary? */
564e0b0ad4SHeiko Carstens 		"	jnh	6f\n"
577f65d183SHeiko Carstens 		"3:	mvcos	0(%[to]),0(%[from]),%[rem]\n"
587f65d183SHeiko Carstens 		"4:	slgr	%[size],%[rem]\n"
594e0b0ad4SHeiko Carstens 		"	j	6f\n"
604e0b0ad4SHeiko Carstens 		"5:	slgr	%[size],%[size]\n"
614e0b0ad4SHeiko Carstens 		"6:\n"
624e0b0ad4SHeiko Carstens 		EX_TABLE(0b, 2b)
634e0b0ad4SHeiko Carstens 		EX_TABLE(1b, 2b)
64afdcc2ceSHeiko Carstens 		EX_TABLE(3b, 6b)
654e0b0ad4SHeiko Carstens 		EX_TABLE(4b, 6b)
66*c3bd8343SHeiko Carstens 		: [size] "+&a" (size), [from] "+&a" (from), [to] "+&a" (to), [rem] "=&a" (rem)
67*c3bd8343SHeiko Carstens 		: [val] "a" (-4096UL), [spec] "d" (spec.val)
68d1e18efaSHeiko Carstens 		: "cc", "memory", "0");
69457f2180SHeiko Carstens 	return size;
70457f2180SHeiko Carstens }
71457f2180SHeiko Carstens 
raw_copy_from_user(void * to,const void __user * from,unsigned long n)7237096003SAl Viro unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
73457f2180SHeiko Carstens {
74432b1cc7SJanis Schoetterl-Glausch 	return raw_copy_from_user_key(to, from, n, 0);
75457f2180SHeiko Carstens }
7637096003SAl Viro EXPORT_SYMBOL(raw_copy_from_user);
77457f2180SHeiko Carstens 
_copy_from_user_key(void * to,const void __user * from,unsigned long n,unsigned long key)78432b1cc7SJanis Schoetterl-Glausch unsigned long _copy_from_user_key(void *to, const void __user *from,
79432b1cc7SJanis Schoetterl-Glausch 				  unsigned long n, unsigned long key)
80432b1cc7SJanis Schoetterl-Glausch {
81432b1cc7SJanis Schoetterl-Glausch 	unsigned long res = n;
82432b1cc7SJanis Schoetterl-Glausch 
83432b1cc7SJanis Schoetterl-Glausch 	might_fault();
84432b1cc7SJanis Schoetterl-Glausch 	if (!should_fail_usercopy()) {
8533b75c1dSAlexander Potapenko 		instrument_copy_from_user_before(to, from, n);
86432b1cc7SJanis Schoetterl-Glausch 		res = raw_copy_from_user_key(to, from, n, key);
8733b75c1dSAlexander Potapenko 		instrument_copy_from_user_after(to, from, n, res);
88432b1cc7SJanis Schoetterl-Glausch 	}
89432b1cc7SJanis Schoetterl-Glausch 	if (unlikely(res))
90432b1cc7SJanis Schoetterl-Glausch 		memset(to + (n - res), 0, res);
91432b1cc7SJanis Schoetterl-Glausch 	return res;
92432b1cc7SJanis Schoetterl-Glausch }
93432b1cc7SJanis Schoetterl-Glausch EXPORT_SYMBOL(_copy_from_user_key);
94432b1cc7SJanis Schoetterl-Glausch 
raw_copy_to_user_key(void __user * to,const void * from,unsigned long size,unsigned long key)954efd417fSVasily Gorbik static unsigned long raw_copy_to_user_key(void __user *to, const void *from,
96432b1cc7SJanis Schoetterl-Glausch 					  unsigned long size, unsigned long key)
97457f2180SHeiko Carstens {
98*c3bd8343SHeiko Carstens 	unsigned long rem;
99012a224eSNico Boehr 	union oac spec = {
100432b1cc7SJanis Schoetterl-Glausch 		.oac1.key = key,
101012a224eSNico Boehr 		.oac1.as = PSW_BITS_AS_SECONDARY,
102432b1cc7SJanis Schoetterl-Glausch 		.oac1.k = 1,
103012a224eSNico Boehr 		.oac1.a = 1,
104012a224eSNico Boehr 	};
105457f2180SHeiko Carstens 
106457f2180SHeiko Carstens 	asm volatile(
107012a224eSNico Boehr 		"	lr	0,%[spec]\n"
10810679e4dSHeiko Carstens 		"0:	mvcos	0(%[to]),0(%[from]),%[size]\n"
1094e0b0ad4SHeiko Carstens 		"1:	jz	5f\n"
1107f65d183SHeiko Carstens 		"	algr	%[size],%[val]\n"
1117f65d183SHeiko Carstens 		"	slgr	%[to],%[val]\n"
1127f65d183SHeiko Carstens 		"	slgr	%[from],%[val]\n"
113457f2180SHeiko Carstens 		"	j	0b\n"
1147f65d183SHeiko Carstens 		"2:	la	%[rem],4095(%[to])\n"	/* rem = to + 4095 */
1157f65d183SHeiko Carstens 		"	nr	%[rem],%[val]\n"	/* rem = (to + 4095) & -4096 */
1167f65d183SHeiko Carstens 		"	slgr	%[rem],%[to]\n"
1177f65d183SHeiko Carstens 		"	clgr	%[size],%[rem]\n"	/* copy crosses next page boundary? */
1184e0b0ad4SHeiko Carstens 		"	jnh	6f\n"
1197f65d183SHeiko Carstens 		"3:	mvcos	0(%[to]),0(%[from]),%[rem]\n"
1207f65d183SHeiko Carstens 		"4:	slgr	%[size],%[rem]\n"
1214e0b0ad4SHeiko Carstens 		"	j	6f\n"
1224e0b0ad4SHeiko Carstens 		"5:	slgr	%[size],%[size]\n"
1234e0b0ad4SHeiko Carstens 		"6:\n"
1244e0b0ad4SHeiko Carstens 		EX_TABLE(0b, 2b)
1254e0b0ad4SHeiko Carstens 		EX_TABLE(1b, 2b)
126afdcc2ceSHeiko Carstens 		EX_TABLE(3b, 6b)
1274e0b0ad4SHeiko Carstens 		EX_TABLE(4b, 6b)
128*c3bd8343SHeiko Carstens 		: [size] "+&a" (size), [to] "+&a" (to), [from] "+&a" (from), [rem] "=&a" (rem)
129*c3bd8343SHeiko Carstens 		: [val] "a" (-4096UL), [spec] "d" (spec.val)
130d1e18efaSHeiko Carstens 		: "cc", "memory", "0");
131457f2180SHeiko Carstens 	return size;
132457f2180SHeiko Carstens }
133457f2180SHeiko Carstens 
raw_copy_to_user(void __user * to,const void * from,unsigned long n)13437096003SAl Viro unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
135457f2180SHeiko Carstens {
136432b1cc7SJanis Schoetterl-Glausch 	return raw_copy_to_user_key(to, from, n, 0);
137457f2180SHeiko Carstens }
13837096003SAl Viro EXPORT_SYMBOL(raw_copy_to_user);
139457f2180SHeiko Carstens 
_copy_to_user_key(void __user * to,const void * from,unsigned long n,unsigned long key)140432b1cc7SJanis Schoetterl-Glausch unsigned long _copy_to_user_key(void __user *to, const void *from,
141432b1cc7SJanis Schoetterl-Glausch 				unsigned long n, unsigned long key)
142432b1cc7SJanis Schoetterl-Glausch {
143432b1cc7SJanis Schoetterl-Glausch 	might_fault();
144432b1cc7SJanis Schoetterl-Glausch 	if (should_fail_usercopy())
145432b1cc7SJanis Schoetterl-Glausch 		return n;
146432b1cc7SJanis Schoetterl-Glausch 	instrument_copy_to_user(to, from, n);
147432b1cc7SJanis Schoetterl-Glausch 	return raw_copy_to_user_key(to, from, n, key);
148432b1cc7SJanis Schoetterl-Glausch }
149432b1cc7SJanis Schoetterl-Glausch EXPORT_SYMBOL(_copy_to_user_key);
150432b1cc7SJanis Schoetterl-Glausch 
__clear_user(void __user * to,unsigned long size)1514efd417fSVasily Gorbik unsigned long __clear_user(void __user *to, unsigned long size)
152457f2180SHeiko Carstens {
153*c3bd8343SHeiko Carstens 	unsigned long rem;
154012a224eSNico Boehr 	union oac spec = {
155012a224eSNico Boehr 		.oac1.as = PSW_BITS_AS_SECONDARY,
156012a224eSNico Boehr 		.oac1.a = 1,
157012a224eSNico Boehr 	};
158457f2180SHeiko Carstens 
159457f2180SHeiko Carstens 	asm volatile(
160012a224eSNico Boehr 		"	lr	0,%[spec]\n"
16110679e4dSHeiko Carstens 		"0:	mvcos	0(%[to]),0(%[zeropg]),%[size]\n"
1624e0b0ad4SHeiko Carstens 		"1:	jz	5f\n"
1637f65d183SHeiko Carstens 		"	algr	%[size],%[val]\n"
1647f65d183SHeiko Carstens 		"	slgr	%[to],%[val]\n"
165457f2180SHeiko Carstens 		"	j	0b\n"
1667f65d183SHeiko Carstens 		"2:	la	%[rem],4095(%[to])\n"	/* rem = to + 4095 */
1677f65d183SHeiko Carstens 		"	nr	%[rem],%[val]\n"	/* rem = (to + 4095) & -4096 */
1687f65d183SHeiko Carstens 		"	slgr	%[rem],%[to]\n"
1697f65d183SHeiko Carstens 		"	clgr	%[size],%[rem]\n"	/* copy crosses next page boundary? */
1704e0b0ad4SHeiko Carstens 		"	jnh	6f\n"
1717f65d183SHeiko Carstens 		"3:	mvcos	0(%[to]),0(%[zeropg]),%[rem]\n"
1727f65d183SHeiko Carstens 		"4:	slgr	%[size],%[rem]\n"
1734e0b0ad4SHeiko Carstens 		"	j	6f\n"
1744e0b0ad4SHeiko Carstens 		"5:	slgr	%[size],%[size]\n"
1754e0b0ad4SHeiko Carstens 		"6:\n"
1764e0b0ad4SHeiko Carstens 		EX_TABLE(0b, 2b)
1774e0b0ad4SHeiko Carstens 		EX_TABLE(1b, 2b)
1784e0b0ad4SHeiko Carstens 		EX_TABLE(3b, 6b)
1794e0b0ad4SHeiko Carstens 		EX_TABLE(4b, 6b)
180*c3bd8343SHeiko Carstens 		: [size] "+&a" (size), [to] "+&a" (to), [rem] "=&a" (rem)
181*c3bd8343SHeiko Carstens 		: [val] "a" (-4096UL), [zeropg] "a" (empty_zero_page), [spec] "d" (spec.val)
182d1e18efaSHeiko Carstens 		: "cc", "memory", "0");
183457f2180SHeiko Carstens 	return size;
184457f2180SHeiko Carstens }
185457f2180SHeiko Carstens EXPORT_SYMBOL(__clear_user);
186