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