xref: /openbmc/linux/arch/s390/lib/uaccess.c (revision 49d6e68f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Standard user space access functions based on mvcp/mvcs and doing
4  *  interesting things in the secondary space mode.
5  *
6  *    Copyright IBM Corp. 2006,2014
7  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
8  *		 Gerald Schaefer (gerald.schaefer@de.ibm.com)
9  */
10 
11 #include <linux/uaccess.h>
12 #include <linux/export.h>
13 #include <linux/mm.h>
14 #include <asm/asm-extable.h>
15 
16 #ifdef CONFIG_DEBUG_ENTRY
debug_user_asce(int exit)17 void debug_user_asce(int exit)
18 {
19 	unsigned long cr1, cr7;
20 
21 	__ctl_store(cr1, 1, 1);
22 	__ctl_store(cr7, 7, 7);
23 	if (cr1 == S390_lowcore.kernel_asce && cr7 == S390_lowcore.user_asce)
24 		return;
25 	panic("incorrect ASCE on kernel %s\n"
26 	      "cr1:    %016lx cr7:  %016lx\n"
27 	      "kernel: %016llx user: %016llx\n",
28 	      exit ? "exit" : "entry", cr1, cr7,
29 	      S390_lowcore.kernel_asce, S390_lowcore.user_asce);
30 }
31 #endif /*CONFIG_DEBUG_ENTRY */
32 
raw_copy_from_user_key(void * to,const void __user * from,unsigned long size,unsigned long key)33 static unsigned long raw_copy_from_user_key(void *to, const void __user *from,
34 					    unsigned long size, unsigned long key)
35 {
36 	unsigned long rem;
37 	union oac spec = {
38 		.oac2.key = key,
39 		.oac2.as = PSW_BITS_AS_SECONDARY,
40 		.oac2.k = 1,
41 		.oac2.a = 1,
42 	};
43 
44 	asm volatile(
45 		"	lr	0,%[spec]\n"
46 		"0:	mvcos	0(%[to]),0(%[from]),%[size]\n"
47 		"1:	jz	5f\n"
48 		"	algr	%[size],%[val]\n"
49 		"	slgr	%[from],%[val]\n"
50 		"	slgr	%[to],%[val]\n"
51 		"	j	0b\n"
52 		"2:	la	%[rem],4095(%[from])\n"	/* rem = from + 4095 */
53 		"	nr	%[rem],%[val]\n"	/* rem = (from + 4095) & -4096 */
54 		"	slgr	%[rem],%[from]\n"
55 		"	clgr	%[size],%[rem]\n"	/* copy crosses next page boundary? */
56 		"	jnh	6f\n"
57 		"3:	mvcos	0(%[to]),0(%[from]),%[rem]\n"
58 		"4:	slgr	%[size],%[rem]\n"
59 		"	j	6f\n"
60 		"5:	slgr	%[size],%[size]\n"
61 		"6:\n"
62 		EX_TABLE(0b, 2b)
63 		EX_TABLE(1b, 2b)
64 		EX_TABLE(3b, 6b)
65 		EX_TABLE(4b, 6b)
66 		: [size] "+&a" (size), [from] "+&a" (from), [to] "+&a" (to), [rem] "=&a" (rem)
67 		: [val] "a" (-4096UL), [spec] "d" (spec.val)
68 		: "cc", "memory", "0");
69 	return size;
70 }
71 
raw_copy_from_user(void * to,const void __user * from,unsigned long n)72 unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
73 {
74 	return raw_copy_from_user_key(to, from, n, 0);
75 }
76 EXPORT_SYMBOL(raw_copy_from_user);
77 
_copy_from_user_key(void * to,const void __user * from,unsigned long n,unsigned long key)78 unsigned long _copy_from_user_key(void *to, const void __user *from,
79 				  unsigned long n, unsigned long key)
80 {
81 	unsigned long res = n;
82 
83 	might_fault();
84 	if (!should_fail_usercopy()) {
85 		instrument_copy_from_user_before(to, from, n);
86 		res = raw_copy_from_user_key(to, from, n, key);
87 		instrument_copy_from_user_after(to, from, n, res);
88 	}
89 	if (unlikely(res))
90 		memset(to + (n - res), 0, res);
91 	return res;
92 }
93 EXPORT_SYMBOL(_copy_from_user_key);
94 
raw_copy_to_user_key(void __user * to,const void * from,unsigned long size,unsigned long key)95 static unsigned long raw_copy_to_user_key(void __user *to, const void *from,
96 					  unsigned long size, unsigned long key)
97 {
98 	unsigned long rem;
99 	union oac spec = {
100 		.oac1.key = key,
101 		.oac1.as = PSW_BITS_AS_SECONDARY,
102 		.oac1.k = 1,
103 		.oac1.a = 1,
104 	};
105 
106 	asm volatile(
107 		"	lr	0,%[spec]\n"
108 		"0:	mvcos	0(%[to]),0(%[from]),%[size]\n"
109 		"1:	jz	5f\n"
110 		"	algr	%[size],%[val]\n"
111 		"	slgr	%[to],%[val]\n"
112 		"	slgr	%[from],%[val]\n"
113 		"	j	0b\n"
114 		"2:	la	%[rem],4095(%[to])\n"	/* rem = to + 4095 */
115 		"	nr	%[rem],%[val]\n"	/* rem = (to + 4095) & -4096 */
116 		"	slgr	%[rem],%[to]\n"
117 		"	clgr	%[size],%[rem]\n"	/* copy crosses next page boundary? */
118 		"	jnh	6f\n"
119 		"3:	mvcos	0(%[to]),0(%[from]),%[rem]\n"
120 		"4:	slgr	%[size],%[rem]\n"
121 		"	j	6f\n"
122 		"5:	slgr	%[size],%[size]\n"
123 		"6:\n"
124 		EX_TABLE(0b, 2b)
125 		EX_TABLE(1b, 2b)
126 		EX_TABLE(3b, 6b)
127 		EX_TABLE(4b, 6b)
128 		: [size] "+&a" (size), [to] "+&a" (to), [from] "+&a" (from), [rem] "=&a" (rem)
129 		: [val] "a" (-4096UL), [spec] "d" (spec.val)
130 		: "cc", "memory", "0");
131 	return size;
132 }
133 
raw_copy_to_user(void __user * to,const void * from,unsigned long n)134 unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
135 {
136 	return raw_copy_to_user_key(to, from, n, 0);
137 }
138 EXPORT_SYMBOL(raw_copy_to_user);
139 
_copy_to_user_key(void __user * to,const void * from,unsigned long n,unsigned long key)140 unsigned long _copy_to_user_key(void __user *to, const void *from,
141 				unsigned long n, unsigned long key)
142 {
143 	might_fault();
144 	if (should_fail_usercopy())
145 		return n;
146 	instrument_copy_to_user(to, from, n);
147 	return raw_copy_to_user_key(to, from, n, key);
148 }
149 EXPORT_SYMBOL(_copy_to_user_key);
150 
__clear_user(void __user * to,unsigned long size)151 unsigned long __clear_user(void __user *to, unsigned long size)
152 {
153 	unsigned long rem;
154 	union oac spec = {
155 		.oac1.as = PSW_BITS_AS_SECONDARY,
156 		.oac1.a = 1,
157 	};
158 
159 	asm volatile(
160 		"	lr	0,%[spec]\n"
161 		"0:	mvcos	0(%[to]),0(%[zeropg]),%[size]\n"
162 		"1:	jz	5f\n"
163 		"	algr	%[size],%[val]\n"
164 		"	slgr	%[to],%[val]\n"
165 		"	j	0b\n"
166 		"2:	la	%[rem],4095(%[to])\n"	/* rem = to + 4095 */
167 		"	nr	%[rem],%[val]\n"	/* rem = (to + 4095) & -4096 */
168 		"	slgr	%[rem],%[to]\n"
169 		"	clgr	%[size],%[rem]\n"	/* copy crosses next page boundary? */
170 		"	jnh	6f\n"
171 		"3:	mvcos	0(%[to]),0(%[zeropg]),%[rem]\n"
172 		"4:	slgr	%[size],%[rem]\n"
173 		"	j	6f\n"
174 		"5:	slgr	%[size],%[size]\n"
175 		"6:\n"
176 		EX_TABLE(0b, 2b)
177 		EX_TABLE(1b, 2b)
178 		EX_TABLE(3b, 6b)
179 		EX_TABLE(4b, 6b)
180 		: [size] "+&a" (size), [to] "+&a" (to), [rem] "=&a" (rem)
181 		: [val] "a" (-4096UL), [zeropg] "a" (empty_zero_page), [spec] "d" (spec.val)
182 		: "cc", "memory", "0");
183 	return size;
184 }
185 EXPORT_SYMBOL(__clear_user);
186